summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-24 01:56:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-24 01:56:37 +0000
commit8f4cc1aaed27bf561cad096d47c24903421c7ab7 (patch)
tree9f8ecf92240a8ef68527ec4b4349e0950d23dc3a
parentReleasing progress-linux version 1:7.0.4-1~progress7.99u1. (diff)
downloadsuricata-8f4cc1aaed27bf561cad096d47c24903421c7ab7.tar.xz
suricata-8f4cc1aaed27bf561cad096d47c24903421c7ab7.zip
Merging upstream version 1:7.0.5.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--ChangeLog30
-rw-r--r--Makefile.in1
-rwxr-xr-xconfigure84
-rw-r--r--configure.ac39
-rw-r--r--contrib/Makefile.in1
-rw-r--r--contrib/file_processor/Action/Makefile.in1
-rw-r--r--contrib/file_processor/Makefile.in1
-rw-r--r--contrib/file_processor/Processor/Makefile.in1
-rw-r--r--doc/Makefile.in1
-rw-r--r--doc/userguide/Makefile.am1
-rw-r--r--doc/userguide/Makefile.in2
-rw-r--r--doc/userguide/capture-hardware/dpdk.rst38
-rw-r--r--doc/userguide/conf.py6
-rw-r--r--doc/userguide/rules/base64-keywords.rst2
-rw-r--r--doc/userguide/suricata.12
-rw-r--r--doc/userguide/suricatactl-filestore.12
-rw-r--r--doc/userguide/suricatactl.12
-rw-r--r--doc/userguide/suricatasc.12
-rw-r--r--doc/userguide/userguide.pdfbin3799748 -> 3801361 bytes
-rw-r--r--ebpf/Makefile.in1
-rw-r--r--etc/Makefile.in1
-rw-r--r--python/Makefile.in1
-rw-r--r--qa/Makefile.in1
-rw-r--r--qa/coccinelle/Makefile.in1
-rw-r--r--rules/Makefile.in1
-rw-r--r--rust/Cargo.toml.in1
-rw-r--r--rust/Makefile.in1
-rw-r--r--rust/derive/Cargo.toml2
-rw-r--r--rust/src/asn1/mod.rs6
-rw-r--r--rust/src/dhcp/logger.rs2
-rw-r--r--rust/src/http2/detect.rs19
-rw-r--r--rust/src/http2/http2.rs2
-rw-r--r--rust/src/http2/logger.rs17
-rw-r--r--rust/src/http2/parser.rs61
-rw-r--r--rust/src/jsonbuilder.rs57
-rw-r--r--rust/src/mqtt/mqtt.rs3
-rw-r--r--rust/src/smb/smb.rs2
-rw-r--r--rust/src/smb/smb1.rs2
-rw-r--r--src/Makefile.in1
-rw-r--r--src/autoconf.h8
-rw-r--r--src/conf-yaml-loader.c15
-rw-r--r--src/datasets.c5
-rw-r--r--src/decode-ipv4.h26
-rw-r--r--src/decode.c1
-rw-r--r--src/decode.h1
-rw-r--r--src/defrag.c1620
-rw-r--r--src/defrag.h1
-rw-r--r--src/detect-dataset.c4
-rw-r--r--src/detect-fast-pattern.c3
-rw-r--r--src/detect-http-server-body.c3
-rw-r--r--src/detect-ipopts.c75
-rw-r--r--src/detect-parse.c12
-rw-r--r--src/flow-timeout.c10
-rw-r--r--src/flow.c2
-rw-r--r--src/output-json-stats.c34
-rw-r--r--src/runmode-af-packet.c6
-rw-r--r--src/runmode-dpdk.c42
-rw-r--r--src/runmode-dpdk.h1
-rw-r--r--src/runmode-netmap.c6
-rw-r--r--src/runmodes.c11
-rw-r--r--src/source-dpdk.c73
-rw-r--r--src/source-dpdk.h1
-rw-r--r--src/source-pcap-file-helper.c1
-rw-r--r--src/tests/detect-http-client-body.c1
-rw-r--r--src/tests/detect-http-server-body.c1
-rw-r--r--src/tests/output-json-stats.c69
-rw-r--r--src/util-base64.c6
-rw-r--r--src/util-dpdk-ice.c12
-rw-r--r--src/util-dpdk-ice.h4
-rw-r--r--src/util-host-info.c36
-rw-r--r--src/util-streaming-buffer.c63
-rw-r--r--suricata-update/CHANGELOG.md4
-rw-r--r--suricata-update/Makefile7
-rw-r--r--suricata-update/Makefile.in1
-rw-r--r--suricata-update/suricata/update/main.py5
-rw-r--r--suricata-update/suricata/update/version.py2
-rw-r--r--suricata.yaml.in1
77 files changed, 1831 insertions, 740 deletions
diff --git a/ChangeLog b/ChangeLog
index 69c9ce3..0099919 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+7.0.5 -- 2024-04-23
+
+Security #6905: base64: off-by-three overflow in DecodeBase64() (7.0.x backport)(CVE 2024-32664)
+Security #6901: http2: timeout logging headers (7.0.x backport)(CVE 2024-32663)
+Security #6893: http2: oom on copying compressed headers (7.0.x backport)(CVE 2024-32663)
+Security #6677: ip-defrag: packet can be considered complete even with holes (7.0.x backport)(CVE 2024-32867)
+Security #6673: ip defrag: final overlapping packet can lead to "hole" in re-assembled data (7.0.x backport)(CVE 2024-32867)
+Security #6672: ip defrag: re-assembly error in bsd policy (7.0.x backport)(CVE 2024-32867)
+Bug #6970: streaming buffer: heap overflows in StreamingBufferAppend()/StreamingBufferAppendNoTrack() (7.0.x backport)
+Bug #6966: improve handling of content encoding: gzip but request_body not actually compressed (7.0.x backport)
+Bug #6958: Assert: BUG_ON(id <= 0 || id > (int)thread_store.threads_size); (7.0.x backport)
+Bug #6949: detect/http.response_body: false positive because not enforcing direction to_client (7.0.x backport)
+Bug #6945: defrag: reassembled packet can have wrong datatype (7.0.x backport)
+Bug #6923: jsonbuilder: serializes Rust f64 NaNs to an invalid literal (7.0.x backport)
+Bug #6919: pcre2 compile warning (7.0.x backport)
+Bug #6907: Fix stats key (7.0.x backport)
+Bug #6890: detect: slowdown in rule parsing (7.0.x backport)
+Bug #6884: rust: clippy 1.77 warning (7.0.x backport)
+Bug #6882: Detect: ipopts keyword misfires (7.0.x backport)
+Bug #6872: dpdk: fix compatibility issues for ice cards (7.0.x backport)
+Bug #6863: BUG_ON triggered from TmThreadsInjectFlowById (7.0.x backport)
+Bug #6859: fast_pattern specification in base64_data shouldn't be allowed (7.0.x backport)
+Bug #6727: stream: stream.drop-invalid drops valid traffic (7.0.x backport)
+Bug #6679: datasets: discard datasets that hit the memcap while loading correctly (7.0.x backport)
+Bug #6313: napatech: display HBA deprecation notice only once
+Optimization #6880: conf: quadratic complexity in yaml loader (7.0.x backport)
+Feature #6947: pcap: datalink type 229 not (yet) supported in module PcapFile (7.0.x backport)
+Feature #6696: dpdk: power saving mode (7.0.x backport)
+Documentation #6912: manpages: use consistant date based on release and/or git commits (7.0.x backport)
+
7.0.4 -- 2024-03-19
Security #6868: eve: excessive ssh long banner logging (7.0.x backport)(CVE 2024-28870)
diff --git a/Makefile.in b/Makefile.in
index ef89168..910bd55 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -317,6 +317,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/configure b/configure
index fb5335d..d17b55d 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for suricata 7.0.4.
+# Generated by GNU Autoconf 2.71 for suricata 7.0.5.
#
#
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -682,8 +682,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='suricata'
PACKAGE_TARNAME='suricata'
-PACKAGE_VERSION='7.0.4'
-PACKAGE_STRING='suricata 7.0.4'
+PACKAGE_VERSION='7.0.5'
+PACKAGE_STRING='suricata 7.0.5'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -745,6 +745,7 @@ e_logcertsdir
e_logfilesdir
e_rundir
e_logdir
+RELEASE_DATE
HAVE_GIT_CMD
HAS_FUZZLDFLAGS_FALSE
HAS_FUZZLDFLAGS_TRUE
@@ -1661,7 +1662,7 @@ 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 suricata 7.0.4 to adapt to many kinds of systems.
+\`configure' configures suricata 7.0.5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1732,7 +1733,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of suricata 7.0.4:";;
+ short | recursive ) echo "Configuration of suricata 7.0.5:";;
esac
cat <<\_ACEOF
@@ -1975,7 +1976,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-suricata configure 7.0.4
+suricata configure 7.0.5
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2567,7 +2568,7 @@ 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 suricata $as_me 7.0.4, which was
+It was created by suricata $as_me 7.0.5, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -4062,7 +4063,7 @@ fi
# Define the identity of the package.
PACKAGE='suricata'
- VERSION='7.0.4'
+ VERSION='7.0.5'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -22946,7 +22947,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by suricata $as_me 7.0.4, which was
+This file was extended by suricata $as_me 7.0.5, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -23014,7 +23015,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-suricata config.status 7.0.4
+suricata config.status 7.0.5
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
@@ -24917,19 +24918,19 @@ fi
fi
pkg_failed=no
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for htp >= 0.5.47" >&5
-printf %s "checking for htp >= 0.5.47... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for htp >= 0.5.48" >&5
+printf %s "checking for htp >= 0.5.48... " >&6; }
if test -n "$LIBHTPMINVERSION_CFLAGS"; then
pkg_cv_LIBHTPMINVERSION_CFLAGS="$LIBHTPMINVERSION_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"htp >= 0.5.47\""; } >&5
- ($PKG_CONFIG --exists --print-errors "htp >= 0.5.47") 2>&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"htp >= 0.5.48\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "htp >= 0.5.48") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_LIBHTPMINVERSION_CFLAGS=`$PKG_CONFIG --cflags "htp >= 0.5.47" 2>/dev/null`
+ pkg_cv_LIBHTPMINVERSION_CFLAGS=`$PKG_CONFIG --cflags "htp >= 0.5.48" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -24941,12 +24942,12 @@ if test -n "$LIBHTPMINVERSION_LIBS"; then
pkg_cv_LIBHTPMINVERSION_LIBS="$LIBHTPMINVERSION_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"htp >= 0.5.47\""; } >&5
- ($PKG_CONFIG --exists --print-errors "htp >= 0.5.47") 2>&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"htp >= 0.5.48\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "htp >= 0.5.48") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_LIBHTPMINVERSION_LIBS=`$PKG_CONFIG --libs "htp >= 0.5.47" 2>/dev/null`
+ pkg_cv_LIBHTPMINVERSION_LIBS=`$PKG_CONFIG --libs "htp >= 0.5.48" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -24967,9 +24968,9 @@ 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.5.47" 2>&1`
+ LIBHTPMINVERSION_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "htp >= 0.5.48" 2>&1`
else
- LIBHTPMINVERSION_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "htp >= 0.5.47" 2>&1`
+ LIBHTPMINVERSION_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "htp >= 0.5.48" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$LIBHTPMINVERSION_PKG_ERRORS" >&5
@@ -25060,7 +25061,7 @@ printf "%s\n" "yes" >&6; }
fi
if test "$libhtp_devver_found" = "no"; then
echo
- echo " ERROR! libhtp was found but it is neither >= 0.5.47, nor the dev 0.5.X"
+ echo " ERROR! libhtp was found but it is neither >= 0.5.48, nor the dev 0.5.X"
echo
exit 1
fi
@@ -34295,14 +34296,8 @@ else
fi
-# get revision
- if test -f ./revision; then
- REVISION=`cat ./revision`
-
-printf "%s\n" "#define REVISION ${REVISION}" >>confdefs.h
-
- else
- # Extract the first word of "git", so it can be a program name with args.
+# get git revision and last commit date
+ # Extract the first word of "git", so it can be a program name with args.
set dummy git; ac_word=$2
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
printf %s "checking for $ac_word... " >&6; }
@@ -34348,18 +34343,33 @@ printf "%s\n" "no" >&6; }
fi
- if test "$HAVE_GIT_CMD" != "no"; then
- if test -d .git ; then
- REVISION=`git rev-parse --short HEAD`
- DATE=`git log -1 --date=short --pretty=format:%cd`
- REVISION="$REVISION $DATE"
+ if test "$HAVE_GIT_CMD" != "no"; then
+ if test -e .git ; then
+ REVISION=`git rev-parse --short HEAD`
+ LAST_COMMIT_DATE=`git log -1 --date=short --pretty=format:%cd`
+ REVISION="$REVISION $LAST_COMMIT_DATE"
printf "%s\n" "#define REVISION ${REVISION}" >>confdefs.h
- fi
fi
fi
+# Get the release date. If LAST_COMMIT_DATE was set in the previous
+# step, use it, otherwise parse it from the ChangeLog.
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for release date" >&5
+printf %s "checking for release date... " >&6; }
+ if test "x$LAST_COMMIT_DATE" != "x"; then
+ RELEASE_DATE=$LAST_COMMIT_DATE
+ else
+ RELEASE_DATE=`awk '/^[0-9\.]+ -- [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/ { print $3; exit }' $srcdir/ChangeLog`
+ if test "x$RELEASE_DATE" = "x"; then
+ as_fn_error $? "Failed to determine release date" "$LINENO" 5
+ fi
+ fi
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${RELEASE_DATE}" >&5
+printf "%s\n" "${RELEASE_DATE}" >&6; }
+
+
# get MAJOR_MINOR version for embedding in configuration file.
MAJOR_MINOR=`expr "${PACKAGE_VERSION}" : "\([0-9]\+\.[0-9]\+\).*"`
@@ -35272,7 +35282,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by suricata $as_me 7.0.4, which was
+This file was extended by suricata $as_me 7.0.5, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -35340,7 +35350,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-suricata config.status 7.0.4
+suricata config.status 7.0.5
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 72f333e..c46ff40 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
- AC_INIT([suricata],[7.0.4])
+ AC_INIT([suricata],[7.0.5])
m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])AM_SILENT_RULES([yes])
AC_CONFIG_HEADERS([src/autoconf.h])
AC_CONFIG_SRCDIR([src/suricata.c])
@@ -1575,12 +1575,12 @@
echo
exit 1
fi
- PKG_CHECK_MODULES(LIBHTPMINVERSION, [htp >= 0.5.47],[libhtp_minver_found="yes"],[libhtp_minver_found="no"])
+ PKG_CHECK_MODULES(LIBHTPMINVERSION, [htp >= 0.5.48],[libhtp_minver_found="yes"],[libhtp_minver_found="no"])
if test "$libhtp_minver_found" = "no"; then
PKG_CHECK_MODULES(LIBHTPDEVVERSION, [htp = 0.5.X],[libhtp_devver_found="yes"],[libhtp_devver_found="no"])
if test "$libhtp_devver_found" = "no"; then
echo
- echo " ERROR! libhtp was found but it is neither >= 0.5.47, nor the dev 0.5.X"
+ echo " ERROR! libhtp was found but it is neither >= 0.5.48, nor the dev 0.5.X"
echo
exit 1
fi
@@ -2480,21 +2480,30 @@ return 0;
AM_CONDITIONAL([HAS_FUZZLDFLAGS], [test "x$has_sanitizefuzzer" = "xyes"])
-# get revision
- if test -f ./revision; then
- REVISION=`cat ./revision`
- AC_DEFINE_UNQUOTED([REVISION],[${REVISION}],[Git revision])
+# get git revision and last commit date
+ AC_PATH_PROG(HAVE_GIT_CMD, git, "no")
+ if test "$HAVE_GIT_CMD" != "no"; then
+ if [ test -e .git ]; then
+ REVISION=`git rev-parse --short HEAD`
+ LAST_COMMIT_DATE=`git log -1 --date=short --pretty=format:%cd`
+ REVISION="$REVISION $LAST_COMMIT_DATE"
+ AC_DEFINE_UNQUOTED([REVISION],[${REVISION}],[Git revision])
+ fi
+ fi
+
+# Get the release date. If LAST_COMMIT_DATE was set in the previous
+# step, use it, otherwise parse it from the ChangeLog.
+ AC_MSG_CHECKING([for release date])
+ if test "x$LAST_COMMIT_DATE" != "x"; then
+ RELEASE_DATE=$LAST_COMMIT_DATE
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`
- DATE=`git log -1 --date=short --pretty=format:%cd`
- REVISION="$REVISION $DATE"
- AC_DEFINE_UNQUOTED([REVISION],[${REVISION}],[Git revision])
- fi
+ RELEASE_DATE=`awk '/^[[0-9\.]]+ -- [[0-9]][[0-9]][[0-9]][[0-9]]-[[0-9]][[0-9]]-[[0-9]][[0-9]]/ { print $3; exit }' $srcdir/ChangeLog`
+ if test "x$RELEASE_DATE" = "x"; then
+ AC_MSG_ERROR([Failed to determine release date])
fi
fi
+ AC_MSG_RESULT([${RELEASE_DATE}])
+ AC_SUBST(RELEASE_DATE)
# get MAJOR_MINOR version for embedding in configuration file.
MAJOR_MINOR=`expr "${PACKAGE_VERSION}" : "\([[0-9]]\+\.[[0-9]]\+\).*"`
diff --git a/contrib/Makefile.in b/contrib/Makefile.in
index a94fe1f..2efb9c9 100644
--- a/contrib/Makefile.in
+++ b/contrib/Makefile.in
@@ -288,6 +288,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/contrib/file_processor/Action/Makefile.in b/contrib/file_processor/Action/Makefile.in
index b2b3f8c..2755fb0 100644
--- a/contrib/file_processor/Action/Makefile.in
+++ b/contrib/file_processor/Action/Makefile.in
@@ -230,6 +230,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/contrib/file_processor/Makefile.in b/contrib/file_processor/Makefile.in
index fd42c12..fc85aff 100644
--- a/contrib/file_processor/Makefile.in
+++ b/contrib/file_processor/Makefile.in
@@ -288,6 +288,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/contrib/file_processor/Processor/Makefile.in b/contrib/file_processor/Processor/Makefile.in
index 7ed0063..9da38d0 100644
--- a/contrib/file_processor/Processor/Makefile.in
+++ b/contrib/file_processor/Processor/Makefile.in
@@ -230,6 +230,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 0bec752..b44a221 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -320,6 +320,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am
index bd15792..8ffede5 100644
--- a/doc/userguide/Makefile.am
+++ b/doc/userguide/Makefile.am
@@ -74,6 +74,7 @@ userguide.pdf: _build/latex/Suricata.pdf
pdf: userguide.pdf
_build/man: manpages/suricata.rst manpages/suricatasc.rst manpages/suricatactl.rst manpages/suricatactl-filestore.rst
+ RELEASE_DATE=$(RELEASE_DATE) \
sysconfdir=$(sysconfdir) \
localstatedir=$(localstatedir) \
version=$(PACKAGE_VERSION) \
diff --git a/doc/userguide/Makefile.in b/doc/userguide/Makefile.in
index 2d0a204..2884e25 100644
--- a/doc/userguide/Makefile.in
+++ b/doc/userguide/Makefile.in
@@ -262,6 +262,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
@@ -640,6 +641,7 @@ uninstall-man: uninstall-man1
@SPHINX_BUILD_TRUE@pdf: userguide.pdf
@SPHINX_BUILD_TRUE@_build/man: manpages/suricata.rst manpages/suricatasc.rst manpages/suricatactl.rst manpages/suricatactl-filestore.rst
+@SPHINX_BUILD_TRUE@ RELEASE_DATE=$(RELEASE_DATE) \
@SPHINX_BUILD_TRUE@ sysconfdir=$(sysconfdir) \
@SPHINX_BUILD_TRUE@ localstatedir=$(localstatedir) \
@SPHINX_BUILD_TRUE@ version=$(PACKAGE_VERSION) \
diff --git a/doc/userguide/capture-hardware/dpdk.rst b/doc/userguide/capture-hardware/dpdk.rst
index 1b9ecae..6be7278 100644
--- a/doc/userguide/capture-hardware/dpdk.rst
+++ b/doc/userguide/capture-hardware/dpdk.rst
@@ -146,3 +146,41 @@ management and worker CPU set.
- worker-cpu-set:
cpu: [ 2,4,6,8 ]
...
+
+Interrupt (power-saving) mode
+-----------------------------
+
+The DPDK is traditionally recognized for its polling mode operation.
+In this mode, CPU cores are continuously querying for packets from
+the Network Interface Card (NIC). While this approach offers benefits like
+reduced latency and improved performance, it might not be the most efficient
+in scenarios with sporadic or low traffic.
+The constant polling can lead to unnecessary CPU consumption.
+To address this, DPDK offers an `interrupt` mode.
+
+The obvious advantage that interrupt mode brings is power efficiency.
+So far in our tests, we haven't observed a decrease in performance. Suricata's
+performance has actually seen a slight improvement.
+The (IPS runmode) users should be aware that interrupts can
+introduce non-deterministic latency. However, the latency should never be
+higher than in other (e.g. AF_PACKET/AF_XDP/...) capture methods.
+
+Interrupt mode in DPDK can be configured on a per-interface basis.
+This allows for a hybrid setup where some workers operate in polling mode,
+while others utilize the interrupt mode.
+The configuration for the interrupt mode can be found and modified in the
+DPDK section of the suricata.yaml file.
+
+Below is a sample configuration that demonstrates how to enable the interrupt mode for a specific interface:
+
+::
+
+ ...
+ dpdk:
+ eal-params:
+ proc-type: primary
+
+ interfaces:
+ - interface: 0000:3b:00.0
+ interrupt-mode: true
+ threads: 4
diff --git a/doc/userguide/conf.py b/doc/userguide/conf.py
index d043a28..959744e 100644
--- a/doc/userguide/conf.py
+++ b/doc/userguide/conf.py
@@ -19,6 +19,10 @@ import re
import subprocess
import datetime
+# Set 'today'. This will be used as the man page date. If an empty
+# string todays date will be used.
+today = os.environ.get('RELEASE_DATE', '')
+
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
# If extensions (or modules to document with autodoc) are in another directory,
@@ -67,7 +71,7 @@ try:
version = os.environ.get('version', None)
if not version:
version = re.search(
- "AC_INIT\(\[suricata\],\s*\[(.*)?\]\)",
+ r"AC_INIT\(\[suricata\],\s*\[(.*)?\]\)",
open("../../configure.ac").read()).groups()[0]
if not version:
version = "unknown"
diff --git a/doc/userguide/rules/base64-keywords.rst b/doc/userguide/rules/base64-keywords.rst
index 7daf0c2..190fdb5 100644
--- a/doc/userguide/rules/base64-keywords.rst
+++ b/doc/userguide/rules/base64-keywords.rst
@@ -62,3 +62,5 @@ Example::
alert http any any -> any any (msg:"Example"; content:"somestring"; http_uri; \
base64_decode:bytes 8, offset 1, relative; \
base64_data; content:"test"; sid:10001; rev:1;)
+
+.. note:: ``fast_pattern`` is ineffective with ``base64_data``
diff --git a/doc/userguide/suricata.1 b/doc/userguide/suricata.1
index 9564f6a..423e397 100644
--- a/doc/userguide/suricata.1
+++ b/doc/userguide/suricata.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "SURICATA" "1" "Mar 19, 2024" "7.0.4" "Suricata"
+.TH "SURICATA" "1" "2024-04-23" "7.0.5" "Suricata"
.SH NAME
suricata \- Suricata
.SH SYNOPSIS
diff --git a/doc/userguide/suricatactl-filestore.1 b/doc/userguide/suricatactl-filestore.1
index 40688f8..4ec5a9f 100644
--- a/doc/userguide/suricatactl-filestore.1
+++ b/doc/userguide/suricatactl-filestore.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "SURICATACTL-FILESTORE" "1" "Mar 19, 2024" "7.0.4" "Suricata"
+.TH "SURICATACTL-FILESTORE" "1" "2024-04-23" "7.0.5" "Suricata"
.SH NAME
suricatactl-filestore \- Perform actions on filestore
.SH SYNOPSIS
diff --git a/doc/userguide/suricatactl.1 b/doc/userguide/suricatactl.1
index 90b0801..a0a1725 100644
--- a/doc/userguide/suricatactl.1
+++ b/doc/userguide/suricatactl.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "SURICATACTL" "1" "Mar 19, 2024" "7.0.4" "Suricata"
+.TH "SURICATACTL" "1" "2024-04-23" "7.0.5" "Suricata"
.SH NAME
suricatactl \- Suricata Control
.SH SYNOPSIS
diff --git a/doc/userguide/suricatasc.1 b/doc/userguide/suricatasc.1
index 40a4bc5..4f54787 100644
--- a/doc/userguide/suricatasc.1
+++ b/doc/userguide/suricatasc.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "SURICATASC" "1" "Mar 19, 2024" "7.0.4" "Suricata"
+.TH "SURICATASC" "1" "2024-04-23" "7.0.5" "Suricata"
.SH NAME
suricatasc \- Tool to interact via unix socket
.SH SYNOPSIS
diff --git a/doc/userguide/userguide.pdf b/doc/userguide/userguide.pdf
index 2ff1757..4b38931 100644
--- a/doc/userguide/userguide.pdf
+++ b/doc/userguide/userguide.pdf
Binary files differ
diff --git a/ebpf/Makefile.in b/ebpf/Makefile.in
index 41b736b..6269cb8 100644
--- a/ebpf/Makefile.in
+++ b/ebpf/Makefile.in
@@ -230,6 +230,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/etc/Makefile.in b/etc/Makefile.in
index 4eede76..05e1827 100644
--- a/etc/Makefile.in
+++ b/etc/Makefile.in
@@ -262,6 +262,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/python/Makefile.in b/python/Makefile.in
index d1e7f1d..f1e2bdd 100644
--- a/python/Makefile.in
+++ b/python/Makefile.in
@@ -242,6 +242,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/qa/Makefile.in b/qa/Makefile.in
index be4a02b..0e54fa2 100644
--- a/qa/Makefile.in
+++ b/qa/Makefile.in
@@ -288,6 +288,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/qa/coccinelle/Makefile.in b/qa/coccinelle/Makefile.in
index da64830..6f27b0f 100644
--- a/qa/coccinelle/Makefile.in
+++ b/qa/coccinelle/Makefile.in
@@ -230,6 +230,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/rules/Makefile.in b/rules/Makefile.in
index a461b14..6f51ced 100644
--- a/rules/Makefile.in
+++ b/rules/Makefile.in
@@ -261,6 +261,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/rust/Cargo.toml.in b/rust/Cargo.toml.in
index 0bac7e1..347391b 100644
--- a/rust/Cargo.toml.in
+++ b/rust/Cargo.toml.in
@@ -2,6 +2,7 @@
name = "suricata"
version = "@PACKAGE_VERSION@"
edition = "2021"
+rust-version = "1.63.0"
[workspace]
members = [".", "./derive"]
diff --git a/rust/Makefile.in b/rust/Makefile.in
index 40e6b76..dc54872 100644
--- a/rust/Makefile.in
+++ b/rust/Makefile.in
@@ -234,6 +234,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@ $(am__append_1) $(am__append_2) \
diff --git a/rust/derive/Cargo.toml b/rust/derive/Cargo.toml
index c697f68..4a749d7 100644
--- a/rust/derive/Cargo.toml
+++ b/rust/derive/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "suricata-derive"
-version = "7.0.4"
+version = "7.0.5"
edition = "2021"
[lib]
diff --git a/rust/src/asn1/mod.rs b/rust/src/asn1/mod.rs
index 4b77b0c..7496d44 100644
--- a/rust/src/asn1/mod.rs
+++ b/rust/src/asn1/mod.rs
@@ -33,7 +33,7 @@ pub struct Asn1<'a>(Vec<BerObject<'a>>);
enum Asn1DecodeError {
InvalidKeywordParameter,
MaxFrames,
- BerError(Err<der_parser::error::BerError>),
+ BerError,
}
/// Enumeration of Asn1 checks
@@ -282,8 +282,8 @@ impl From<std::num::TryFromIntError> for Asn1DecodeError {
}
impl From<Err<der_parser::error::BerError>> for Asn1DecodeError {
- fn from(e: Err<der_parser::error::BerError>) -> Asn1DecodeError {
- Asn1DecodeError::BerError(e)
+ fn from(_e: Err<der_parser::error::BerError>) -> Asn1DecodeError {
+ Asn1DecodeError::BerError
}
}
diff --git a/rust/src/dhcp/logger.rs b/rust/src/dhcp/logger.rs
index 3c86b1b..a9d8d98 100644
--- a/rust/src/dhcp/logger.rs
+++ b/rust/src/dhcp/logger.rs
@@ -89,7 +89,7 @@ impl DHCPLogger {
js.set_uint("id", header.txid as u64)?;
js.set_string("client_mac",
- &format_addr_hex(&header.clienthw.to_vec()))?;
+ &format_addr_hex(&header.clienthw))?;
js.set_string("assigned_ip", &dns_print_addr(&header.yourip))?;
if self.extended {
diff --git a/rust/src/http2/detect.rs b/rust/src/http2/detect.rs
index 52b4119..67933b6 100644
--- a/rust/src/http2/detect.rs
+++ b/rust/src/http2/detect.rs
@@ -23,6 +23,7 @@ use crate::core::Direction;
use crate::detect::uint::{detect_match_uint, DetectUintData};
use std::ffi::CStr;
use std::str::FromStr;
+use std::rc::Rc;
fn http2_tx_has_frametype(
tx: &mut HTTP2Transaction, direction: Direction, value: u8,
@@ -404,7 +405,7 @@ fn http2_frames_get_header_firstvalue<'a>(
for frame in frames {
if let Some(blocks) = http2_header_blocks(frame) {
for block in blocks.iter() {
- if block.name == name.as_bytes() {
+ if block.name.as_ref() == name.as_bytes() {
return Ok(&block.value);
}
}
@@ -428,7 +429,7 @@ pub fn http2_frames_get_header_value_vec(
for frame in frames {
if let Some(blocks) = http2_header_blocks(frame) {
for block in blocks.iter() {
- if block.name == name.as_bytes() {
+ if block.name.as_ref() == name.as_bytes() {
if found == 0 {
vec.extend_from_slice(&block.value);
found = 1;
@@ -465,7 +466,7 @@ fn http2_frames_get_header_value<'a>(
for frame in frames {
if let Some(blocks) = http2_header_blocks(frame) {
for block in blocks.iter() {
- if block.name == name.as_bytes() {
+ if block.name.as_ref() == name.as_bytes() {
if found == 0 {
single = Ok(&block.value);
found = 1;
@@ -920,8 +921,8 @@ fn http2_tx_set_header(state: &mut HTTP2State, name: &[u8], input: &[u8]) {
};
let mut blocks = Vec::new();
let b = parser::HTTP2FrameHeaderBlock {
- name: name.to_vec(),
- value: input.to_vec(),
+ name: Rc::new(name.to_vec()),
+ value: Rc::new(input.to_vec()),
error: parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
sizeupdate: 0,
};
@@ -1063,15 +1064,15 @@ mod tests {
};
let mut blocks = Vec::new();
let b = parser::HTTP2FrameHeaderBlock {
- name: "Host".as_bytes().to_vec(),
- value: "abc.com".as_bytes().to_vec(),
+ name: "Host".as_bytes().to_vec().into(),
+ value: "abc.com".as_bytes().to_vec().into(),
error: parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
sizeupdate: 0,
};
blocks.push(b);
let b2 = parser::HTTP2FrameHeaderBlock {
- name: "Host".as_bytes().to_vec(),
- value: "efg.net".as_bytes().to_vec(),
+ name: "Host".as_bytes().to_vec().into(),
+ value: "efg.net".as_bytes().to_vec().into(),
error: parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
sizeupdate: 0,
};
diff --git a/rust/src/http2/http2.rs b/rust/src/http2/http2.rs
index b62ccb9..23aaf26 100644
--- a/rust/src/http2/http2.rs
+++ b/rust/src/http2/http2.rs
@@ -208,7 +208,7 @@ impl HTTP2Transaction {
let mut authority = None;
let mut host = None;
for block in blocks {
- if block.name == b"content-encoding" {
+ if block.name.as_ref() == b"content-encoding" {
self.decoder.http2_encoding_fromvec(&block.value, dir);
} else if block.name.eq_ignore_ascii_case(b":authority") {
authority = Some(&block.value);
diff --git a/rust/src/http2/logger.rs b/rust/src/http2/logger.rs
index d25f852..a117a54 100644
--- a/rust/src/http2/logger.rs
+++ b/rust/src/http2/logger.rs
@@ -19,7 +19,8 @@ use super::http2::{HTTP2Frame, HTTP2FrameTypeData, HTTP2Transaction};
use super::parser;
use crate::jsonbuilder::{JsonBuilder, JsonError};
use std;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
+use std::rc::Rc;
#[derive(Hash, PartialEq, Eq, Debug)]
enum HeaderName {
@@ -35,10 +36,20 @@ fn log_http2_headers<'a>(
blocks: &'a [parser::HTTP2FrameHeaderBlock], js: &mut JsonBuilder,
common: &mut HashMap<HeaderName, &'a Vec<u8>>,
) -> Result<(), JsonError> {
+ let mut logged_headers = HashSet::new();
for block in blocks {
- js.start_object()?;
+ // delay js.start_object() because we skip suplicate headers
match block.error {
parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess => {
+ if Rc::strong_count(&block.name) > 2 {
+ // more than one reference in headers table + current headers
+ let ptr = Rc::as_ptr(&block.name) as usize;
+ if !logged_headers.insert(ptr) {
+ // only log once
+ continue;
+ }
+ }
+ js.start_object()?;
js.set_string_from_bytes("name", &block.name)?;
js.set_string_from_bytes("value", &block.value)?;
if let Ok(name) = std::str::from_utf8(&block.name) {
@@ -66,9 +77,11 @@ fn log_http2_headers<'a>(
}
}
parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate => {
+ js.start_object()?;
js.set_uint("table_size_update", block.sizeupdate)?;
}
_ => {
+ js.start_object()?;
js.set_string("error", &block.error.to_string())?;
}
}
diff --git a/rust/src/http2/parser.rs b/rust/src/http2/parser.rs
index adabeb2..1a46437 100644
--- a/rust/src/http2/parser.rs
+++ b/rust/src/http2/parser.rs
@@ -30,6 +30,7 @@ use nom7::sequence::tuple;
use nom7::{Err, IResult};
use std::fmt;
use std::str::FromStr;
+use std::rc::Rc;
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq, FromPrimitive, Debug)]
@@ -295,8 +296,8 @@ fn http2_frame_header_static(n: u64, dyn_headers: &HTTP2DynTable) -> Option<HTTP
};
if !name.is_empty() {
return Some(HTTP2FrameHeaderBlock {
- name: name.as_bytes().to_vec(),
- value: value.as_bytes().to_vec(),
+ name: Rc::new(name.as_bytes().to_vec()),
+ value: Rc::new(value.as_bytes().to_vec()),
error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
sizeupdate: 0,
});
@@ -304,23 +305,23 @@ fn http2_frame_header_static(n: u64, dyn_headers: &HTTP2DynTable) -> Option<HTTP
//use dynamic table
if n == 0 {
return Some(HTTP2FrameHeaderBlock {
- name: Vec::new(),
- value: Vec::new(),
+ name: Rc::new(Vec::new()),
+ value: Rc::new(Vec::new()),
error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIndex0,
sizeupdate: 0,
});
} else if dyn_headers.table.len() + HTTP2_STATIC_HEADERS_NUMBER < n as usize {
return Some(HTTP2FrameHeaderBlock {
- name: Vec::new(),
- value: Vec::new(),
+ name: Rc::new(Vec::new()),
+ value: Rc::new(Vec::new()),
error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeNotIndexed,
sizeupdate: 0,
});
} else {
let indyn = dyn_headers.table.len() - (n as usize - HTTP2_STATIC_HEADERS_NUMBER);
let headcopy = HTTP2FrameHeaderBlock {
- name: dyn_headers.table[indyn].name.to_vec(),
- value: dyn_headers.table[indyn].value.to_vec(),
+ name: dyn_headers.table[indyn].name.clone(),
+ value: dyn_headers.table[indyn].value.clone(),
error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
sizeupdate: 0,
};
@@ -348,8 +349,10 @@ impl fmt::Display for HTTP2HeaderDecodeStatus {
#[derive(Clone, Debug)]
pub struct HTTP2FrameHeaderBlock {
- pub name: Vec<u8>,
- pub value: Vec<u8>,
+ // Use Rc reference counted so that indexed headers do not get copied.
+ // Otherwise, this leads to quadratic complexity in memory occupation.
+ pub name: Rc<Vec<u8>>,
+ pub value: Rc<Vec<u8>>,
pub error: HTTP2HeaderDecodeStatus,
pub sizeupdate: u64,
}
@@ -391,7 +394,7 @@ fn http2_parse_headers_block_literal_common<'a>(
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
let (i3, name, error) = if index == 0 {
match http2_parse_headers_block_string(input) {
- Ok((r, n)) => Ok((r, n, HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess)),
+ Ok((r, n)) => Ok((r, Rc::new(n), HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess)),
Err(e) => Err(e),
}
} else {
@@ -403,7 +406,7 @@ fn http2_parse_headers_block_literal_common<'a>(
)),
None => Ok((
input,
- Vec::new(),
+ Rc::new(Vec::new()),
HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeNotIndexed,
)),
}
@@ -413,7 +416,7 @@ fn http2_parse_headers_block_literal_common<'a>(
i4,
HTTP2FrameHeaderBlock {
name,
- value,
+ value: Rc::new(value),
error,
sizeupdate: 0,
},
@@ -435,8 +438,8 @@ fn http2_parse_headers_block_literal_incindex<'a>(
match r {
Ok((r, head)) => {
let headcopy = HTTP2FrameHeaderBlock {
- name: head.name.to_vec(),
- value: head.value.to_vec(),
+ name: head.name.clone(),
+ value: head.value.clone(),
error: head.error,
sizeupdate: 0,
};
@@ -556,8 +559,8 @@ fn http2_parse_headers_block_dynamic_size<'a>(
return Ok((
i3,
HTTP2FrameHeaderBlock {
- name: Vec::new(),
- value: Vec::new(),
+ name: Rc::new(Vec::new()),
+ value: Rc::new(Vec::new()),
error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate,
sizeupdate: maxsize2,
},
@@ -614,8 +617,8 @@ fn http2_parse_headers_blocks<'a>(
// if we error from http2_parse_var_uint, we keep the first parsed headers
if err.code == ErrorKind::LengthValue {
blocks.push(HTTP2FrameHeaderBlock {
- name: Vec::new(),
- value: Vec::new(),
+ name: Rc::new(Vec::new()),
+ value: Rc::new(Vec::new()),
error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIntegerOverflow,
sizeupdate: 0,
});
@@ -765,8 +768,8 @@ mod tests {
match r0 {
Ok((remainder, hd)) => {
// Check the first message.
- assert_eq!(hd.name, ":method".as_bytes().to_vec());
- assert_eq!(hd.value, "GET".as_bytes().to_vec());
+ assert_eq!(hd.name, ":method".as_bytes().to_vec().into());
+ assert_eq!(hd.value, "GET".as_bytes().to_vec().into());
// And we should have no bytes left.
assert_eq!(remainder.len(), 0);
}
@@ -782,8 +785,8 @@ mod tests {
match r1 {
Ok((remainder, hd)) => {
// Check the first message.
- assert_eq!(hd.name, "accept".as_bytes().to_vec());
- assert_eq!(hd.value, "*/*".as_bytes().to_vec());
+ assert_eq!(hd.name, "accept".as_bytes().to_vec().into());
+ assert_eq!(hd.value, "*/*".as_bytes().to_vec().into());
// And we should have no bytes left.
assert_eq!(remainder.len(), 0);
assert_eq!(dynh.table.len(), 1);
@@ -802,8 +805,8 @@ mod tests {
match result {
Ok((remainder, hd)) => {
// Check the first message.
- assert_eq!(hd.name, ":authority".as_bytes().to_vec());
- assert_eq!(hd.value, "localhost:3000".as_bytes().to_vec());
+ assert_eq!(hd.name, ":authority".as_bytes().to_vec().into());
+ assert_eq!(hd.value, "localhost:3000".as_bytes().to_vec().into());
// And we should have no bytes left.
assert_eq!(remainder.len(), 0);
assert_eq!(dynh.table.len(), 2);
@@ -820,8 +823,8 @@ mod tests {
match r3 {
Ok((remainder, hd)) => {
// same as before
- assert_eq!(hd.name, ":authority".as_bytes().to_vec());
- assert_eq!(hd.value, "localhost:3000".as_bytes().to_vec());
+ assert_eq!(hd.name, ":authority".as_bytes().to_vec().into());
+ assert_eq!(hd.value, "localhost:3000".as_bytes().to_vec().into());
// And we should have no bytes left.
assert_eq!(remainder.len(), 0);
assert_eq!(dynh.table.len(), 2);
@@ -856,8 +859,8 @@ mod tests {
match r2 {
Ok((remainder, hd)) => {
// Check the first message.
- assert_eq!(hd.name, ":path".as_bytes().to_vec());
- assert_eq!(hd.value, "/doc/manual/html/index.html".as_bytes().to_vec());
+ assert_eq!(hd.name, ":path".as_bytes().to_vec().into());
+ assert_eq!(hd.value, "/doc/manual/html/index.html".as_bytes().to_vec().into());
// And we should have no bytes left.
assert_eq!(remainder.len(), 0);
assert_eq!(dynh.table.len(), 2);
diff --git a/rust/src/jsonbuilder.rs b/rust/src/jsonbuilder.rs
index 7264be5..8b42966 100644
--- a/rust/src/jsonbuilder.rs
+++ b/rust/src/jsonbuilder.rs
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020 Open Information Security Foundation
+/* Copyright (C) 2020-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@@ -435,7 +435,7 @@ impl JsonBuilder {
return Err(JsonError::InvalidState);
}
}
- self.push_str(&val.to_string())?;
+ self.push_float(val)?;
Ok(self)
}
@@ -650,7 +650,7 @@ impl JsonBuilder {
self.push('"')?;
self.push_str(key)?;
self.push_str("\":")?;
- self.push_str(&val.to_string())?;
+ self.push_float(val)?;
Ok(self)
}
@@ -681,6 +681,15 @@ impl JsonBuilder {
self.buf.capacity()
}
+ fn push_float(&mut self, val: f64) -> Result<(), JsonError> {
+ if val.is_nan() || val.is_infinite() {
+ self.push_str("null")?;
+ } else {
+ self.push_str(&val.to_string())?;
+ }
+ Ok(())
+ }
+
/// Encode a string into the buffer, escaping as needed.
///
/// The string is encoded into an intermediate vector as its faster
@@ -1339,6 +1348,48 @@ mod test {
jb.close().unwrap();
assert_eq!(jb.buf, r#"[1.1,2.2]"#);
}
+
+ #[test]
+ fn test_set_nan() {
+ let mut jb = JsonBuilder::try_new_object().unwrap();
+ jb.set_float("nan", f64::NAN).unwrap();
+ jb.close().unwrap();
+ assert_eq!(jb.buf, r#"{"nan":null}"#);
+ }
+
+ #[test]
+ fn test_append_nan() {
+ let mut jb = JsonBuilder::try_new_array().unwrap();
+ jb.append_float(f64::NAN).unwrap();
+ jb.close().unwrap();
+ assert_eq!(jb.buf, r#"[null]"#);
+ }
+
+ #[test]
+ fn test_set_inf() {
+ let mut jb = JsonBuilder::try_new_object().unwrap();
+ jb.set_float("inf", f64::INFINITY).unwrap();
+ jb.close().unwrap();
+ assert_eq!(jb.buf, r#"{"inf":null}"#);
+
+ let mut jb = JsonBuilder::try_new_object().unwrap();
+ jb.set_float("inf", f64::NEG_INFINITY).unwrap();
+ jb.close().unwrap();
+ assert_eq!(jb.buf, r#"{"inf":null}"#);
+ }
+
+ #[test]
+ fn test_append_inf() {
+ let mut jb = JsonBuilder::try_new_array().unwrap();
+ jb.append_float(f64::INFINITY).unwrap();
+ jb.close().unwrap();
+ assert_eq!(jb.buf, r#"[null]"#);
+
+ let mut jb = JsonBuilder::try_new_array().unwrap();
+ jb.append_float(f64::NEG_INFINITY).unwrap();
+ jb.close().unwrap();
+ assert_eq!(jb.buf, r#"[null]"#);
+ }
}
// Escape table as seen in serde-json (MIT/Apache license)
diff --git a/rust/src/mqtt/mqtt.rs b/rust/src/mqtt/mqtt.rs
index 8260251..35f3c6d 100644
--- a/rust/src/mqtt/mqtt.rs
+++ b/rust/src/mqtt/mqtt.rs
@@ -749,8 +749,7 @@ export_state_data_get!(rs_mqtt_get_state_data, MQTTState);
#[no_mangle]
pub unsafe extern "C" fn rs_mqtt_register_parser(cfg_max_msg_len: u32) {
let default_port = CString::new("[1883]").unwrap();
- let max_msg_len = &mut MAX_MSG_LEN;
- *max_msg_len = cfg_max_msg_len;
+ MAX_MSG_LEN = cfg_max_msg_len;
let parser = RustParser {
name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
default_port: default_port.as_ptr(),
diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs
index d6b0a56..45d2cdc 100644
--- a/rust/src/smb/smb.rs
+++ b/rust/src/smb/smb.rs
@@ -1045,7 +1045,7 @@ impl SMBState {
pub fn get_service_for_guid(&self, guid: &[u8]) -> (&'static str, bool)
{
- let (name, is_dcerpc) = match self.guid2name_map.get(&guid.to_vec()) {
+ let (name, is_dcerpc) = match self.guid2name_map.get(guid) {
Some(n) => {
let mut s = n.as_slice();
// skip leading \ if we have it
diff --git a/rust/src/smb/smb1.rs b/rust/src/smb/smb1.rs
index 9d7d47e..3a04c72 100644
--- a/rust/src/smb/smb1.rs
+++ b/rust/src/smb/smb1.rs
@@ -482,7 +482,7 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and
state.ssn2vec_map.insert(name_key, name_val);
let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
- let tx = state.new_create_tx(&cr.file_name.to_vec(),
+ let tx = state.new_create_tx(&cr.file_name,
cr.disposition, del, dir, tx_hdr);
tx.vercmd.set_smb1_cmd(command);
SCLogDebug!("TS CREATE TX {} created", tx.id);
diff --git a/src/Makefile.in b/src/Makefile.in
index 4f15923..229aaef 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1233,6 +1233,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/src/autoconf.h b/src/autoconf.h
index 336c550..457a903 100644
--- a/src/autoconf.h
+++ b/src/autoconf.h
@@ -696,7 +696,7 @@
#define PACKAGE_NAME "suricata"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "suricata 7.0.4"
+#define PACKAGE_STRING "suricata 7.0.5"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "suricata"
@@ -705,7 +705,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "7.0.4"
+#define PACKAGE_VERSION "7.0.5"
/* Pcre code unit width is 8 bits */
#define PCRE2_CODE_UNIT_WIDTH 8
@@ -723,7 +723,7 @@
/* #undef PROFILING */
/* Git revision */
-#define REVISION d8bad3b1a 2024-03-19
+#define REVISION c4cf7b09f 2024-04-23
/* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
@@ -743,7 +743,7 @@
/* #undef UNITTESTS */
/* Version number of package */
-#define VERSION "7.0.4"
+#define VERSION "7.0.5"
/* Enable Windows WinDivert support for inline IDP */
/* #undef WINDIVERT */
diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c
index ea64563..463eb2e 100644
--- a/src/conf-yaml-loader.c
+++ b/src/conf-yaml-loader.c
@@ -394,8 +394,19 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int
if (inseq) {
char sequence_node_name[DEFAULT_NAME_LEN];
snprintf(sequence_node_name, DEFAULT_NAME_LEN, "%d", seq_idx++);
- ConfNode *seq_node = ConfNodeLookupChild(node,
- sequence_node_name);
+ ConfNode *seq_node = NULL;
+ if (was_empty < 0) {
+ // initialize was_empty
+ if (TAILQ_EMPTY(&node->head)) {
+ was_empty = 1;
+ } else {
+ was_empty = 0;
+ }
+ }
+ // we only check if the node's list was not empty at first
+ if (was_empty == 0) {
+ seq_node = ConfNodeLookupChild(node, sequence_node_name);
+ }
if (seq_node != NULL) {
/* The sequence node has already been set, probably
* from the command line. Remove it so it gets
diff --git a/src/datasets.c b/src/datasets.c
index d89ed8d..01ef5bb 100644
--- a/src/datasets.c
+++ b/src/datasets.c
@@ -746,6 +746,11 @@ Dataset *DatasetGet(const char *name, enum DatasetTypes type, const char *save,
break;
}
+ if (set->hash && SC_ATOMIC_GET(set->hash->memcap_reached)) {
+ SCLogError("dataset too large for set memcap");
+ goto out_err;
+ }
+
SCLogDebug("set %p/%s type %u save %s load %s",
set, set->name, set->type, set->save, set->load);
diff --git a/src/decode-ipv4.h b/src/decode-ipv4.h
index d247fa9..a825007 100644
--- a/src/decode-ipv4.h
+++ b/src/decode-ipv4.h
@@ -154,20 +154,18 @@ typedef struct IPV4Hdr_
memset(&p->ip4vars, 0x00, sizeof(p->ip4vars)); \
} while (0)
-enum IPV4OptionFlags {
- IPV4_OPT_FLAG_EOL = 0,
- IPV4_OPT_FLAG_NOP,
- IPV4_OPT_FLAG_RR,
- IPV4_OPT_FLAG_TS,
- IPV4_OPT_FLAG_QS,
- IPV4_OPT_FLAG_LSRR,
- IPV4_OPT_FLAG_SSRR,
- IPV4_OPT_FLAG_SID,
- IPV4_OPT_FLAG_SEC,
- IPV4_OPT_FLAG_CIPSO,
- IPV4_OPT_FLAG_RTRALT,
- IPV4_OPT_FLAG_ESEC,
-};
+#define IPV4_OPT_FLAG_EOL BIT_U16(1)
+#define IPV4_OPT_FLAG_NOP BIT_U16(2)
+#define IPV4_OPT_FLAG_RR BIT_U16(3)
+#define IPV4_OPT_FLAG_TS BIT_U16(4)
+#define IPV4_OPT_FLAG_QS BIT_U16(5)
+#define IPV4_OPT_FLAG_LSRR BIT_U16(6)
+#define IPV4_OPT_FLAG_SSRR BIT_U16(7)
+#define IPV4_OPT_FLAG_SID BIT_U16(8)
+#define IPV4_OPT_FLAG_SEC BIT_U16(9)
+#define IPV4_OPT_FLAG_CIPSO BIT_U16(10)
+#define IPV4_OPT_FLAG_RTRALT BIT_U16(11)
+#define IPV4_OPT_FLAG_ESEC BIT_U16(12)
/* helper structure with parsed ipv4 info */
typedef struct IPV4Vars_
diff --git a/src/decode.c b/src/decode.c
index 5cdeeea..13c6541 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -408,7 +408,6 @@ Packet *PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, u
}
p->recursion_level = parent->recursion_level; /* NOT incremented */
p->ts = parent->ts;
- p->datalink = DLT_RAW;
p->tenant_id = parent->tenant_id;
/* tell new packet it's part of a tunnel */
SET_TUNNEL_PKT(p);
diff --git a/src/decode.h b/src/decode.h
index dedfbb0..4516d37 100644
--- a/src/decode.h
+++ b/src/decode.h
@@ -974,6 +974,7 @@ void DecodeUnregisterCounters(void);
* Libpcap on at least OpenBSD returns 101 as datalink type for RAW pcaps though. */
#define LINKTYPE_RAW2 101
#define LINKTYPE_IPV4 228
+#define LINKTYPE_IPV6 229
#define LINKTYPE_GRE_OVER_IP 778
#define LINKTYPE_CISCO_HDLC DLT_C_HDLC
#define PPP_OVER_GRE 11
diff --git a/src/defrag.c b/src/defrag.c
index 71cf420..4596d72 100644
--- a/src/defrag.c
+++ b/src/defrag.c
@@ -104,26 +104,6 @@ static DefragContext *defrag_context;
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
/**
- * 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
@@ -266,7 +246,7 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
}
/* Check that we have all the data. Relies on the fact that
- * fragments are inserted if frag_offset order. */
+ * fragments are inserted in frag_offset order. */
Frag *frag = NULL;
size_t len = 0;
RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
@@ -276,7 +256,8 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
goto done;
}
else {
- len += frag->data_len;
+ /* Update the packet length to the largest known data offset. */
+ len = MAX(len, frag->offset + frag->data_len);
}
}
@@ -288,17 +269,27 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
}
PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
rp->flags |= PKT_REBUILT_FRAGMENT;
- rp->recursion_level = p->recursion_level;
+ rp->datalink = tracker->datalink;
int fragmentable_offset = 0;
uint16_t fragmentable_len = 0;
uint16_t hlen = 0;
int ip_hdr_offset = 0;
+ /* Assume more frags. */
+ uint16_t prev_offset = 0;
+ bool more_frags = 1;
+
RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
frag, frag->data_len, frag->offset, frag->pcap_cnt);
+ /* Previous fragment has no more fragments, and this packet
+ * doesn't overlap. We're done. */
+ if (!more_frags && frag->offset > prev_offset) {
+ break;
+ }
+
if (frag->skip)
continue;
if (frag->ltrim >= frag->data_len)
@@ -339,9 +330,16 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
fragmentable_len = frag->offset + frag->data_len;
}
- if (!frag->more_frags) {
- break;
- }
+ /* Even if this fragment is flagged as having no more
+ * fragments, still continue. The next fragment may have the
+ * same offset with data that is preferred.
+ *
+ * For example, DefragBsdFragmentAfterNoMfIpv{4,6}Test
+ *
+ * This is due to not all fragments being completely trimmed,
+ * but relying on the copy ordering. */
+ more_frags = frag->more_frags;
+ prev_offset = frag->offset;
}
SCLogDebug("ip_hdr_offset %u, hlen %" PRIu16 ", fragmentable_len %" PRIu16, ip_hdr_offset, hlen,
@@ -417,7 +415,7 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
goto done;
}
else {
- len += frag->data_len;
+ len = MAX(len, frag->offset + frag->data_len);
}
}
}
@@ -430,13 +428,23 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
goto error_remove_tracker;
}
PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
+ rp->flags |= PKT_REBUILT_FRAGMENT;
+ rp->datalink = tracker->datalink;
uint16_t unfragmentable_len = 0;
int fragmentable_offset = 0;
uint16_t fragmentable_len = 0;
int ip_hdr_offset = 0;
uint8_t next_hdr = 0;
+
+ /* Assume more frags. */
+ uint16_t prev_offset = 0;
+ bool more_frags = 1;
+
RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
+ if (!more_frags && frag->offset > prev_offset) {
+ break;
+ }
if (frag->skip)
continue;
if (frag->data_len - frag->ltrim <= 0)
@@ -481,9 +489,16 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
fragmentable_len = frag->offset + frag->data_len;
}
- if (!frag->more_frags) {
- break;
- }
+ /* Even if this fragment is flagged as having no more
+ * fragments, still continue. The next fragment may have the
+ * same offset with data that is preferred.
+ *
+ * For example, DefragBsdFragmentAfterNoMfIpv{4,6}Test
+ *
+ * This is due to not all fragments being completely trimmed,
+ * but relying on the copy ordering. */
+ more_frags = frag->more_frags;
+ prev_offset = frag->offset;
}
rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
@@ -660,16 +675,45 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker,
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;
+ if (prev->offset <= frag_offset) {
+ /* We prefer the data from the previous
+ * fragment, so trim off the data in the new
+ * fragment that exists in the previous
+ * fragment. */
+ uint16_t prev_end = prev->offset + prev->data_len;
+ if (prev_end > frag_end) {
+ /* Just skip. */
+ /* TODO: Set overlap flag. */
+ goto done;
+ }
+ ltrim = prev_end - frag_offset;
+
+ if ((next != NULL) && (frag_end > next->offset)) {
+ next->ltrim = frag_end - next->offset;
+ }
+
+ goto insert;
}
+
+ /* If the end of this fragment overlaps the start
+ * of the previous fragment, then trim up the
+ * start of previous fragment so this fragment is
+ * used.
+ *
+ * See:
+ * DefragBsdSubsequentOverlapsStartOfOriginal.
+ */
+ if (frag_offset <= prev->offset && frag_end > prev->offset + prev->ltrim) {
+ uint16_t prev_ltrim = frag_end - prev->offset;
+ if (prev_ltrim > prev->ltrim) {
+ prev->ltrim = prev_ltrim;
+ }
+ }
+
if ((next != NULL) && (frag_end > next->offset)) {
next->ltrim = frag_end - next->offset;
}
- if ((frag_offset < prev->offset) &&
- (frag_end >= prev->offset + prev->data_len)) {
- prev->skip = 1;
- }
+
goto insert;
}
break;
@@ -861,6 +905,9 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker,
#ifdef DEBUG
new->pcap_cnt = pcap_cnt;
#endif
+ if (frag_offset == 0) {
+ tracker->datalink = p->datalink;
+ }
IP_FRAGMENTS_RB_INSERT(&tracker->fragment_tree, new);
@@ -1093,8 +1140,8 @@ void DefragDestroy(void)
* Allocate a test packet. Nothing to fancy, just a simple IP packet
* with some payload of no particular protocol.
*/
-static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
- const char content, int content_len)
+static Packet *BuildIpv4TestPacket(
+ uint8_t proto, uint16_t id, uint16_t off, int mf, const char content, int content_len)
{
Packet *p = NULL;
int hlen = 20;
@@ -1167,8 +1214,79 @@ error:
return NULL;
}
-static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off,
- int mf, const char content, int content_len)
+/**
+ * Allocate a test packet, much like BuildIpv4TestPacket, but with
+ * the full content provided by the caller.
+ */
+static Packet *BuildIpv4TestPacketWithContent(
+ uint8_t proto, uint16_t id, uint16_t off, int mf, const uint8_t *content, int content_len)
+{
+ Packet *p = NULL;
+ int hlen = 20;
+ int ttl = 64;
+ IPV4Hdr ip4h;
+
+ p = SCCalloc(1, sizeof(*p) + default_packet_size);
+ if (unlikely(p == NULL))
+ return NULL;
+
+ PacketInit(p);
+
+ struct timeval tval;
+ gettimeofday(&tval, NULL);
+ p->ts = SCTIME_FROM_TIMEVAL(&tval);
+ ip4h.ip_verhl = 4 << 4;
+ ip4h.ip_verhl |= hlen >> 2;
+ ip4h.ip_len = htons(hlen + content_len);
+ ip4h.ip_id = htons(id);
+ if (mf)
+ ip4h.ip_off = htons(IP_MF | off);
+ else
+ ip4h.ip_off = htons(off);
+ ip4h.ip_ttl = ttl;
+ ip4h.ip_proto = proto;
+
+ 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);
+
+ PacketCopyDataOffset(p, hlen, content, content_len);
+ SET_PKT_LEN(p, hlen + content_len);
+
+ p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
+
+ /* 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) != proto)
+ goto error;
+
+ return p;
+error:
+ if (p != NULL)
+ SCFree(p);
+ return NULL;
+}
+
+static Packet *BuildIpv6TestPacket(
+ uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t content, int content_len)
{
Packet *p = NULL;
uint8_t *pcontent;
@@ -1238,6 +1356,71 @@ error:
return NULL;
}
+static Packet *BuildIpv6TestPacketWithContent(
+ uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t *content, int content_len)
+{
+ Packet *p = NULL;
+ IPV6Hdr ip6h;
+
+ p = SCCalloc(1, sizeof(*p) + default_packet_size);
+ if (unlikely(p == NULL))
+ return NULL;
+
+ PacketInit(p);
+
+ struct timeval tval;
+ gettimeofday(&tval, NULL);
+ p->ts = SCTIME_FROM_TIMEVAL(&tval);
+
+ 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. */
+ IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
+ fh->ip6fh_nxt = proto;
+ fh->ip6fh_ident = htonl(id);
+ fh->ip6fh_offlg = htons((off << 3) | mf);
+
+ DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
+
+ PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), content, content_len);
+ SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
+
+ 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:
+ if (p != NULL)
+ SCFree(p);
+ return NULL;
+}
+
/**
* Test the simplest possible re-assembly scenario. All packet in
* order and no overlaps.
@@ -1251,11 +1434,11 @@ static int DefragInOrderSimpleTest(void)
DefragInit();
- p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
+ p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
FAIL_IF_NULL(p2);
- p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
+ p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
FAIL_IF_NULL(p3);
FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
@@ -1303,11 +1486,11 @@ static int DefragReverseSimpleTest(void)
DefragInit();
- p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
+ p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
FAIL_IF_NULL(p2);
- p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
+ p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
FAIL_IF_NULL(p3);
FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
@@ -1347,7 +1530,7 @@ static int DefragReverseSimpleTest(void)
* Test the simplest possible re-assembly scenario. All packet in
* order and no overlaps.
*/
-static int IPV6DefragInOrderSimpleTest(void)
+static int DefragInOrderSimpleIpv6Test(void)
{
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
Packet *reassembled = NULL;
@@ -1356,11 +1539,11 @@ static int IPV6DefragInOrderSimpleTest(void)
DefragInit();
- p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
+ p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
+ p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
FAIL_IF_NULL(p2);
- p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
+ p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
FAIL_IF_NULL(p3);
FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
@@ -1394,7 +1577,7 @@ static int IPV6DefragInOrderSimpleTest(void)
PASS;
}
-static int IPV6DefragReverseSimpleTest(void)
+static int DefragReverseSimpleIpv6Test(void)
{
DefragContext *dc = NULL;
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
@@ -1407,11 +1590,11 @@ static int IPV6DefragReverseSimpleTest(void)
dc = DefragContextNew();
FAIL_IF_NULL(dc);
- p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
+ p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
+ p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
FAIL_IF_NULL(p2);
- p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
+ p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
FAIL_IF_NULL(p3);
FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
@@ -1444,8 +1627,7 @@ static int IPV6DefragReverseSimpleTest(void)
PASS;
}
-static int DefragDoSturgesNovakTest(int policy, u_char *expected,
- size_t expected_len)
+static int DefragDoSturgesNovakTest(int policy, uint8_t *expected, size_t expected_len)
{
int i;
@@ -1463,60 +1645,60 @@ static int DefragDoSturgesNovakTest(int policy, u_char *expected,
* Original fragments.
*/
- /* A*24 at 0. */
- packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
+ /* <1> A*24 at 0. */
+ packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
- /* B*15 at 32. */
- packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
+ /* <2> B*16 at 32. */
+ packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
- /* C*24 at 48. */
- packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
+ /* <3> C*24 at 48. */
+ packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
- /* D*8 at 80. */
- packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
+ /* <3_1> D*8 at 80. */
+ packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
- /* E*16 at 104. */
- packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
+ /* <3_2> E*16 at 104. */
+ packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
- /* F*24 at 120. */
- packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
+ /* <3_3> F*24 at 120. */
+ packets[5] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
- /* G*16 at 144. */
- packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
+ /* <3_4> G*16 at 144. */
+ packets[6] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
- /* H*16 at 160. */
- packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
+ /* <3_5> H*16 at 160. */
+ packets[7] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
- /* I*8 at 176. */
- packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
+ /* <3_6> I*8 at 176. */
+ packets[8] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
/*
* Overlapping subsequent fragments.
*/
- /* J*32 at 8. */
- packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
+ /* <4> J*32 at 8. */
+ packets[9] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
- /* K*24 at 48. */
- packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
+ /* <5> K*24 at 48. */
+ packets[10] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
- /* L*24 at 72. */
- packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
+ /* <6> L*24 at 72. */
+ packets[11] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
- /* M*24 at 96. */
- packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
+ /* <7> M*24 at 96. */
+ packets[12] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
- /* N*8 at 128. */
- packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
+ /* <8> N*8 at 128. */
+ packets[13] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
- /* O*8 at 152. */
- packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
+ /* <9> O*8 at 152. */
+ packets[14] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
- /* P*8 at 160. */
- packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
+ /* <10> P*8 at 160. */
+ packets[15] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
- /* Q*16 at 176. */
- packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
+ /* <11> Q*16 at 176. */
+ packets[16] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
default_policy = policy;
@@ -1542,8 +1724,15 @@ static int DefragDoSturgesNovakTest(int policy, u_char *expected,
FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192);
-
- FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0);
+ FAIL_IF(expected_len != 192);
+
+ if (memcmp(expected, GET_PKT_DATA(reassembled) + 20, expected_len) != 0) {
+ printf("Expected:\n");
+ PrintRawDataFp(stdout, expected, expected_len);
+ printf("Got:\n");
+ PrintRawDataFp(stdout, GET_PKT_DATA(reassembled) + 20, GET_PKT_LEN(reassembled) - 20);
+ FAIL;
+ }
SCFree(reassembled);
/* Make sure all frags were returned back to the pool. */
@@ -1556,8 +1745,7 @@ static int DefragDoSturgesNovakTest(int policy, u_char *expected,
PASS;
}
-static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
- size_t expected_len)
+static int DefragDoSturgesNovakIpv6Test(int policy, uint8_t *expected, size_t expected_len)
{
int i;
@@ -1575,60 +1763,60 @@ static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
* Original fragments.
*/
- /* A*24 at 0. */
- packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
+ /* <1> A*24 at 0. */
+ packets[0] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
- /* B*15 at 32. */
- packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
+ /* <2> B*16 at 32. */
+ packets[1] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
- /* C*24 at 48. */
- packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
+ /* <3> C*24 at 48. */
+ packets[2] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
- /* D*8 at 80. */
- packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
+ /* <3_1> D*8 at 80. */
+ packets[3] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
- /* E*16 at 104. */
- packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
+ /* <3_2> E*16 at 104. */
+ packets[4] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
- /* F*24 at 120. */
- packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
+ /* <3_3> F*24 at 120. */
+ packets[5] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
- /* G*16 at 144. */
- packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
+ /* <3_4> G*16 at 144. */
+ packets[6] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
- /* H*16 at 160. */
- packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
+ /* <3_5> H*16 at 160. */
+ packets[7] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
- /* I*8 at 176. */
- packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
+ /* <3_6> I*8 at 176. */
+ packets[8] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
/*
* Overlapping subsequent fragments.
*/
- /* J*32 at 8. */
- packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
+ /* <4> J*32 at 8. */
+ packets[9] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
- /* K*24 at 48. */
- packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
+ /* <5> K*24 at 48. */
+ packets[10] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
- /* L*24 at 72. */
- packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
+ /* <6> L*24 at 72. */
+ packets[11] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
- /* M*24 at 96. */
- packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
+ /* <7> M*24 at 96. */
+ packets[12] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
- /* N*8 at 128. */
- packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
+ /* <8> N*8 at 128. */
+ packets[13] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
- /* O*8 at 152. */
- packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
+ /* <9> O*8 at 152. */
+ packets[14] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
- /* P*8 at 160. */
- packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
+ /* <10> P*8 at 160. */
+ packets[15] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
- /* Q*16 at 176. */
- packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
+ /* <11> Q*16 at 176. */
+ packets[16] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
default_policy = policy;
@@ -1667,35 +1855,61 @@ static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
PASS;
}
+/* Define data that matches the naming "Target-Based Fragmentation
+ * Reassembly".
+ *
+ * For example, the data refers to a fragment of data as <1>, or <3_6>
+ * and uses these to diagram the input fragments and the resulting
+ * policies. We build test cases for the papers scenario but assign
+ * specific values to each segment.
+ */
+#define D_1 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'
+#define D_2 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B'
+#define D_3 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C'
+#define D_3_1 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'
+#define D_3_2 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E'
+#define D_3_3 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F'
+#define D_3_4 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G'
+#define D_3_5 'H', 'H', 'H', 'H', 'H', 'H', 'H', 'H'
+#define D_3_6 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I'
+#define D_4 'J', 'J', 'J', 'J', 'J', 'J', 'J', 'J'
+#define D_5 'K', 'K', 'K', 'K', 'K', 'K', 'K', 'K'
+#define D_6 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
+#define D_7 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M'
+#define D_8 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'
+#define D_9 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'
+#define D_10 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'
+#define D_11 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q'
+
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"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_4,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
@@ -1703,69 +1917,68 @@ DefragSturgesNovakBsdTest(void)
PASS;
}
-static int IPV6DefragSturgesNovakBsdTest(void)
+static int DefragSturgesNovakBsdIpv6Test(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"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_4,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
- FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
- sizeof(expected)));
+ FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_BSD, expected, sizeof(expected)));
PASS;
}
static int DefragSturgesNovakLinuxIpv4Test(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"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_4,
+ D_2,
+ D_5,
+ D_5,
+ D_5,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_10,
+ D_3_5,
+ D_11,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
@@ -1773,69 +1986,68 @@ static int DefragSturgesNovakLinuxIpv4Test(void)
PASS;
}
-static int IPV6DefragSturgesNovakLinuxTest(void)
+static int DefragSturgesNovakLinuxIpv6Test(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"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_4,
+ D_2,
+ D_5,
+ D_5,
+ D_5,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_10,
+ D_3_5,
+ D_11,
+ D_11,
};
- FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
- sizeof(expected)));
+ FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LINUX, expected, sizeof(expected)));
PASS;
}
static int DefragSturgesNovakWindowsIpv4Test(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"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_3_2,
+ D_3_2,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
@@ -1843,69 +2055,68 @@ static int DefragSturgesNovakWindowsIpv4Test(void)
PASS;
}
-static int IPV6DefragSturgesNovakWindowsTest(void)
+static int DefragSturgesNovakWindowsIpv6Test(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"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_3_2,
+ D_3_2,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
- FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
- sizeof(expected)));
+ FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)));
PASS;
}
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"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
@@ -1913,69 +2124,68 @@ static int DefragSturgesNovakSolarisTest(void)
PASS;
}
-static int IPV6DefragSturgesNovakSolarisTest(void)
+static int DefragSturgesNovakSolarisIpv6Test(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"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
- FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
- sizeof(expected)));
+ FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)));
PASS;
}
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"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_3_1,
+ D_6,
+ D_7,
+ D_3_2,
+ D_3_2,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
@@ -1983,69 +2193,68 @@ static int DefragSturgesNovakFirstTest(void)
PASS;
}
-static int IPV6DefragSturgesNovakFirstTest(void)
+static int DefragSturgesNovakFirstIpv6Test(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"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_3_1,
+ D_6,
+ D_7,
+ D_3_2,
+ D_3_2,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
- return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
- sizeof(expected));
+ return DefragDoSturgesNovakIpv6Test(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"
+ uint8_t expected[] = {
+ D_1,
+ D_4,
+ D_4,
+ D_4,
+ D_4,
+ D_2,
+ D_5,
+ D_5,
+ D_5,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_8,
+ D_3_3,
+ D_3_4,
+ D_9,
+ D_10,
+ D_3_5,
+ D_11,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
@@ -2053,38 +2262,37 @@ DefragSturgesNovakLastTest(void)
PASS;
}
-static int IPV6DefragSturgesNovakLastTest(void)
+static int DefragSturgesNovakLastIpv6Test(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"
+ uint8_t expected[] = {
+ D_1,
+ D_4,
+ D_4,
+ D_4,
+ D_4,
+ D_2,
+ D_5,
+ D_5,
+ D_5,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_8,
+ D_3_3,
+ D_3_4,
+ D_9,
+ D_10,
+ D_3_5,
+ D_11,
+ D_11,
};
- FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
- sizeof(expected)));
+ FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LAST, expected, sizeof(expected)));
PASS;
}
@@ -2099,7 +2307,7 @@ static int DefragTimeoutTest(void)
/* Load in 16 packets. */
for (i = 0; i < 16; i++) {
- Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
+ Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, i, 0, 1, 'A' + i, 16);
FAIL_IF_NULL(p);
Packet *tp = Defrag(NULL, NULL, p);
@@ -2109,7 +2317,7 @@ static int DefragTimeoutTest(void)
/* 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(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
+ Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
FAIL_IF_NULL(p);
p->ts = SCTIME_ADD_SECS(p->ts, defrag_context->timeout + 1);
@@ -2134,7 +2342,7 @@ static int DefragTimeoutTest(void)
* fail. The fix was simple, but this unit test is just to make sure
* its not introduced.
*/
-static int DefragIPv4NoDataTest(void)
+static int DefragNoDataIpv4Test(void)
{
DefragContext *dc = NULL;
Packet *p = NULL;
@@ -2146,7 +2354,7 @@ static int DefragIPv4NoDataTest(void)
FAIL_IF_NULL(dc);
/* This packet has an offset > 0, more frags set to 0 and no data. */
- p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
+ p = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
FAIL_IF_NULL(p);
/* We do not expect a packet returned. */
@@ -2163,7 +2371,7 @@ static int DefragIPv4NoDataTest(void)
PASS;
}
-static int DefragIPv4TooLargeTest(void)
+static int DefragTooLargeIpv4Test(void)
{
DefragContext *dc = NULL;
Packet *p = NULL;
@@ -2175,7 +2383,7 @@ static int DefragIPv4TooLargeTest(void)
/* Create a fragment that would extend past the max allowable size
* for an IPv4 packet. */
- p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
+ p = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
FAIL_IF_NULL(p);
/* We do not expect a packet returned. */
@@ -2206,9 +2414,9 @@ static int DefragVlanTest(void)
DefragInit();
- p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
+ p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
FAIL_IF_NULL(p2);
/* With no VLAN IDs set, packets should re-assemble. */
@@ -2238,9 +2446,9 @@ static int DefragVlanQinQTest(void)
DefragInit();
- p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
+ p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
FAIL_IF_NULL(p2);
/* With no VLAN IDs set, packets should re-assemble. */
@@ -2272,9 +2480,9 @@ static int DefragVlanQinQinQTest(void)
DefragInit();
- Packet *p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
+ Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- Packet *p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
+ Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
FAIL_IF_NULL(p2);
/* With no VLAN IDs set, packets should re-assemble. */
@@ -2308,7 +2516,7 @@ static int DefragTrackerReuseTest(void)
/* Build a packet, its not a fragment but shouldn't matter for
* this test. */
- p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
FAIL_IF_NULL(p1);
/* Get a tracker. It shouldn't look like its already in use. */
@@ -2355,9 +2563,9 @@ static int DefragMfIpv4Test(void)
DefragInit();
- Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
- Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
- Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
+ Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
+ Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
+ Packet *p3 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
p = Defrag(NULL, NULL, p1);
@@ -2374,6 +2582,10 @@ static int DefragMfIpv4Test(void)
* fragments should be in the re-assembled packet. */
FAIL_IF(IPV4_GET_IPLEN(p) != 36);
+ /* Verify the payload of the IPv4 packet. */
+ uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
+ FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV4Hdr), expected_payload, sizeof(expected_payload)));
+
SCFree(p1);
SCFree(p2);
SCFree(p3);
@@ -2398,9 +2610,9 @@ static int DefragMfIpv6Test(void)
DefragInit();
- Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
- Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
- Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
+ Packet *p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
+ Packet *p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
+ Packet *p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
p = Defrag(NULL, NULL, p1);
@@ -2417,6 +2629,10 @@ static int DefragMfIpv6Test(void)
* of 2 fragments, so 16. */
FAIL_IF(IPV6_GET_PLEN(p) != 16);
+ /* Verify the payload of the IPv4 packet. */
+ uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
+ FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV6Hdr), expected_payload, sizeof(expected_payload)));
+
SCFree(p1);
SCFree(p2);
SCFree(p3);
@@ -2436,11 +2652,11 @@ static int DefragTestBadProto(void)
DefragInit();
- p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
+ p2 = BuildIpv4TestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
FAIL_IF_NULL(p2);
- p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
+ p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
FAIL_IF_NULL(p3);
FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1));
@@ -2461,19 +2677,19 @@ static int DefragTestBadProto(void)
*/
static int DefragTestJeremyLinux(void)
{
- char expected[] = "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "BBBBBBBB"
- "BBBBBBBB"
- "DDDDDDDD"
- "DDDDDD";
+ uint8_t expected[] = "AAAAAAAA"
+ "AAAAAAAA"
+ "AAAAAAAA"
+ "CCCCCCCC"
+ "CCCCCCCC"
+ "CCCCCCCC"
+ "CCCCCCCC"
+ "CCCCCCCC"
+ "CCCCCCCC"
+ "BBBBBBBB"
+ "BBBBBBBB"
+ "DDDDDDDD"
+ "DDDDDD";
DefragInit();
default_policy = DEFRAG_POLICY_LINUX;
@@ -2482,10 +2698,10 @@ static int DefragTestJeremyLinux(void)
Packet *packets[4];
int i = 0;
- packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
- packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
- packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
- packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
+ packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
+ packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
+ packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
+ packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
Packet *r = Defrag(NULL, NULL, packets[0]);
FAIL_IF_NOT_NULL(r);
@@ -2510,6 +2726,401 @@ static int DefragTestJeremyLinux(void)
PASS;
}
+/**
+ * | 0 | 8 | 16 | 24 | 32 |
+ * |----------|----------|----------|----------|----------|
+ * | AAAAAAAA | AAAAAAAA |
+ * | | BBBBBBBB | BBBBBBBB | | |
+ * | | | CCCCCCCC | CCCCCCCC | |
+ * | DDDDDDDD | | | | |
+ *
+ * | DDDDDDDD | BBBBBBBB | BBBBBBBB | CCCCCCCC | AAAAAAAA |
+ */
+static int DefragBsdFragmentAfterNoMfIpv4Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[4];
+
+ packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
+ packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
+ packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
+ packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ uint8_t expected[] = {
+ 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
+ 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
+ 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
+ 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
+ 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
+ };
+ // clang-format on
+
+ if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
+ printf("Expected:\n");
+ PrintRawDataFp(stdout, expected, sizeof(expected));
+ printf("Got:\n");
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
+ FAIL;
+ }
+
+ DefragDestroy();
+ PASS;
+}
+
+static int DefragBsdFragmentAfterNoMfIpv6Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[4];
+
+ packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
+ packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
+ packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
+ packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ uint8_t expected[] = {
+ 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
+ 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
+ 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
+ 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
+ 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
+ };
+ // clang-format on
+
+ if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
+ printf("Expected:\n");
+ PrintRawDataFp(stdout, expected, sizeof(expected));
+ printf("Got:\n");
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
+ FAIL;
+ }
+
+ DefragDestroy();
+ PASS;
+}
+
+static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[4];
+
+ /* Packet 1: off=16, mf=1 */
+ packets[0] = BuildIpv4TestPacketWithContent(
+ IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
+
+ /* Packet 2: off=8, mf=1 */
+ packets[1] = BuildIpv4TestPacketWithContent(
+ IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16);
+
+ /* Packet 3: off=0, mf=1: IP and ICMP header. */
+ packets[2] = BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
+
+ /* Packet 4: off=8, mf=1 */
+ packets[3] =
+ BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ const uint8_t expected[] = {
+ // AACCBBDD
+ // AACCDDBB
+ // AABBDDCC
+ // DDCCBBAA
+ 'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
+ 'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
+ 'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
+ 'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
+ };
+ // clang-format on
+
+ FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20 + 8, sizeof(expected)) != 0);
+
+ DefragDestroy();
+ PASS;
+}
+
+static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[4];
+
+ /* Packet 1: off=16, mf=1 */
+ packets[0] = BuildIpv6TestPacketWithContent(
+ IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
+
+ /* Packet 2: off=8, mf=1 */
+ packets[1] = BuildIpv6TestPacketWithContent(
+ IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16);
+
+ /* Packet 3: off=0, mf=1: IP and ICMP header. */
+ packets[2] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
+
+ /* Packet 4: off=8, mf=1 */
+ packets[3] =
+ BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ const uint8_t expected[] = {
+ // AACCBBDD
+ // AACCDDBB
+ // AABBDDCC
+ // DDCCBBAA
+ 'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
+ 'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
+ 'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
+ 'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
+ };
+ // clang-format on
+
+ FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 40 + 8, sizeof(expected)) != 0);
+
+ DefragDestroy();
+ PASS;
+}
+
+/**
+ * #### Input
+ *
+ * | 96 (0) | 104 (8) | 112 (16) | 120 (24) |
+ * |----------|----------|----------|----------|
+ * | | EEEEEEEE | EEEEEEEE | EEEEEEEE |
+ * | MMMMMMMM | MMMMMMMM | MMMMMMMM | |
+ *
+ * #### Expected Output
+ *
+ * | MMMMMMMM | MMMMMMMM | MMMMMMMM | EEEEEEEE |
+ */
+static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[2];
+
+ packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
+ packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ const uint8_t expected[] = {
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
+ };
+ // clang-format on
+
+ if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
+ printf("Expected:\n");
+ PrintRawDataFp(stdout, expected, sizeof(expected));
+ printf("Got:\n");
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
+ FAIL;
+ }
+
+ PASS;
+}
+
+static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[2];
+
+ packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
+ packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ const uint8_t expected[] = {
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
+ };
+ // clang-format on
+
+ if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
+ printf("Expected:\n");
+ PrintRawDataFp(stdout, expected, sizeof(expected));
+ printf("Got:\n");
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
+ FAIL;
+ }
+
+ PASS;
+}
+
+/**
+ * Reassembly should fail.
+ *
+ * |0 |8 |16 |24 |32 |40 |48 |
+ * |========|========|========|========|========|========|========|
+ * | | |AABBCCDD|AABBDDCC| | | |
+ * | | | | | |AACCBBDD| |
+ * | |AACCDDBB|AADDBBCC| | | | |
+ * |ZZZZZZZZ| | | | | | |
+ * | | | | | | |DDCCBBAA|
+ */
+static int DefragBsdMissingFragmentIpv4Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[5];
+
+ packets[0] = BuildIpv4TestPacketWithContent(
+ IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
+
+ packets[1] =
+ BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
+
+ packets[2] = BuildIpv4TestPacketWithContent(
+ IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
+
+ /* ICMP header. */
+ packets[3] = BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
+
+ packets[4] =
+ BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[4]);
+ FAIL_IF_NOT_NULL(r);
+
+#if 0
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
+#endif
+
+ for (int i = 0; i < 5; i++) {
+ SCFree(packets[i]);
+ }
+
+ DefragDestroy();
+
+ PASS;
+}
+
+static int DefragBsdMissingFragmentIpv6Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[5];
+
+ packets[0] = BuildIpv6TestPacketWithContent(
+ IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
+
+ packets[1] =
+ BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
+
+ packets[2] = BuildIpv6TestPacketWithContent(
+ IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
+
+ /* ICMP header. */
+ packets[3] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
+
+ packets[4] =
+ BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[4]);
+ FAIL_IF_NOT_NULL(r);
+
+#if 0
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
+#endif
+
+ for (int i = 0; i < 5; i++) {
+ SCFree(packets[i]);
+ }
+
+ DefragDestroy();
+
+ PASS;
+}
+
#endif /* UNITTESTS */
void DefragRegisterTests(void)
@@ -2527,23 +3138,17 @@ void DefragRegisterTests(void)
UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
- UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest);
- UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest);
-
- UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest);
- UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest);
- UtRegisterTest("IPV6DefragSturgesNovakBsdTest",
- IPV6DefragSturgesNovakBsdTest);
- UtRegisterTest("IPV6DefragSturgesNovakLinuxTest",
- IPV6DefragSturgesNovakLinuxTest);
- UtRegisterTest("IPV6DefragSturgesNovakWindowsTest",
- IPV6DefragSturgesNovakWindowsTest);
- UtRegisterTest("IPV6DefragSturgesNovakSolarisTest",
- IPV6DefragSturgesNovakSolarisTest);
- UtRegisterTest("IPV6DefragSturgesNovakFirstTest",
- IPV6DefragSturgesNovakFirstTest);
- UtRegisterTest("IPV6DefragSturgesNovakLastTest",
- IPV6DefragSturgesNovakLastTest);
+ UtRegisterTest("DefragNoDataIpv4Test", DefragNoDataIpv4Test);
+ UtRegisterTest("DefragTooLargeIpv4Test", DefragTooLargeIpv4Test);
+
+ UtRegisterTest("DefragInOrderSimpleIpv6Test", DefragInOrderSimpleIpv6Test);
+ UtRegisterTest("DefragReverseSimpleIpv6Test", DefragReverseSimpleIpv6Test);
+ UtRegisterTest("DefragSturgesNovakBsdIpv6Test", DefragSturgesNovakBsdIpv6Test);
+ UtRegisterTest("DefragSturgesNovakLinuxIpv6Test", DefragSturgesNovakLinuxIpv6Test);
+ UtRegisterTest("DefragSturgesNovakWindowsIpv6Test", DefragSturgesNovakWindowsIpv6Test);
+ UtRegisterTest("DefragSturgesNovakSolarisIpv6Test", DefragSturgesNovakSolarisIpv6Test);
+ UtRegisterTest("DefragSturgesNovakFirstIpv6Test", DefragSturgesNovakFirstIpv6Test);
+ UtRegisterTest("DefragSturgesNovakLastIpv6Test", DefragSturgesNovakLastIpv6Test);
UtRegisterTest("DefragVlanTest", DefragVlanTest);
UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
@@ -2555,5 +3160,16 @@ void DefragRegisterTests(void)
UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
+
+ UtRegisterTest("DefragBsdFragmentAfterNoMfIpv4Test", DefragBsdFragmentAfterNoMfIpv4Test);
+ UtRegisterTest("DefragBsdFragmentAfterNoMfIpv6Test", DefragBsdFragmentAfterNoMfIpv6Test);
+ UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test",
+ DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test);
+ UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test",
+ DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test);
+ UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2", DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2);
+ UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2", DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2);
+ UtRegisterTest("DefragBsdMissingFragmentIpv4Test", DefragBsdMissingFragmentIpv4Test);
+ UtRegisterTest("DefragBsdMissingFragmentIpv6Test", DefragBsdMissingFragmentIpv6Test);
#endif /* UNITTESTS */
}
diff --git a/src/defrag.h b/src/defrag.h
index 11e6a61..93fe872 100644
--- a/src/defrag.h
+++ b/src/defrag.h
@@ -106,6 +106,7 @@ typedef struct DefragTracker_ {
Address src_addr; /**< Source address for this tracker. */
Address dst_addr; /**< Destination address for this tracker. */
+ int datalink; /**< datalink for reassembled packet, set by first fragment */
SCTime_t timeout; /**< When this tracker will timeout. */
uint32_t host_timeout; /**< Host timeout, statically assigned from the yaml */
diff --git a/src/detect-dataset.c b/src/detect-dataset.c
index 3d29646..69eaf81 100644
--- a/src/detect-dataset.c
+++ b/src/detect-dataset.c
@@ -407,10 +407,6 @@ int DetectDatasetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst
SCLogError("failed to set up dataset '%s'.", name);
return -1;
}
- if (set->hash && SC_ATOMIC_GET(set->hash->memcap_reached)) {
- SCLogError("dataset too large for set memcap");
- return -1;
- }
cd = SCCalloc(1, sizeof(DetectDatasetData));
if (unlikely(cd == NULL))
diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c
index b82f327..ef6007a 100644
--- a/src/detect-fast-pattern.c
+++ b/src/detect-fast-pattern.c
@@ -274,6 +274,9 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c
}
}
}
+ if (SigMatchListSMBelongsTo(s, pm) == DETECT_SM_LIST_BASE64_DATA) {
+ SCLogInfo("fast_pattern is ineffective with base64_data");
+ }
cd->flags |= DETECT_CONTENT_FAST_PATTERN;
return 0;
}
diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c
index 98f0ec5..28833a8 100644
--- a/src/detect-http-server-body.c
+++ b/src/detect-http-server-body.c
@@ -124,6 +124,9 @@ static int DetectHttpServerBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
return -1;
+ // file data is on both directions, but we only take the one to client here
+ s->flags |= SIG_FLAG_TOCLIENT;
+ s->flags &= ~SIG_FLAG_TOSERVER;
return 0;
}
diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c
index 105751c..01b4712 100644
--- a/src/detect-ipopts.c
+++ b/src/detect-ipopts.c
@@ -25,23 +25,13 @@
#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 "detect-ipopts.h"
#include "util-unittest.h"
-#define PARSE_REGEX "\\S[A-z]"
-
-static DetectParseRegex parse_regex;
-
static int DetectIpOptsMatch (DetectEngineThreadCtx *, Packet *,
const Signature *, const SigMatchCtx *);
static int DetectIpOptsSetup (DetectEngineCtx *, Signature *, const char *);
@@ -64,7 +54,6 @@ void DetectIpOptsRegister (void)
#ifdef UNITTESTS
sigmatch_table[DETECT_IPOPTS].RegisterTests = IpOptsRegisterTests;
#endif
- DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
}
/**
@@ -173,11 +162,7 @@ static int DetectIpOptsMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
if (!de || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p))
return 0;
- if (p->ip4vars.opts_set & de->ipopt) {
- return 1;
- }
-
- return 0;
+ return (p->ip4vars.opts_set & de->ipopt) == de->ipopt;
}
/**
@@ -191,42 +176,30 @@ static int DetectIpOptsMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
*/
static DetectIpOptsData *DetectIpOptsParse (const char *rawstr)
{
- int i;
- DetectIpOptsData *de = NULL;
- int found = 0;
-
- pcre2_match_data *match = NULL;
- int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
- if (ret < 1) {
- SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
- goto error;
- }
+ if (rawstr == NULL || strlen(rawstr) == 0)
+ return NULL;
+ int i;
+ bool found = false;
for(i = 0; ipopts[i].ipopt_name != NULL; i++) {
if((strcasecmp(ipopts[i].ipopt_name,rawstr)) == 0) {
- found = 1;
+ found = true;
break;
}
}
- if(found == 0)
- goto error;
+ if (!found) {
+ SCLogError("unknown IP option specified \"%s\"", rawstr);
+ return NULL;
+ }
- de = SCMalloc(sizeof(DetectIpOptsData));
+ DetectIpOptsData *de = SCMalloc(sizeof(DetectIpOptsData));
if (unlikely(de == NULL))
- goto error;
+ return NULL;
de->ipopt = ipopts[i].code;
- pcre2_match_data_free(match);
return de;
-
-error:
- if (match) {
- pcre2_match_data_free(match);
- }
- if (de) SCFree(de);
- return NULL;
}
/**
@@ -242,10 +215,8 @@ error:
*/
static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
- DetectIpOptsData *de = NULL;
SigMatch *sm = NULL;
-
- de = DetectIpOptsParse(rawstr);
+ DetectIpOptsData *de = DetectIpOptsParse(rawstr);
if (de == NULL)
goto error;
@@ -275,8 +246,9 @@ error:
*/
void DetectIpOptsFree(DetectEngineCtx *de_ctx, void *de_ptr)
{
- DetectIpOptsData *de = (DetectIpOptsData *)de_ptr;
- if(de) SCFree(de);
+ if (de_ptr) {
+ SCFree(de_ptr);
+ }
}
/*
@@ -381,6 +353,20 @@ static int IpOptsTestParse04 (void)
}
/**
+ * \test IpOptsTestParse05 tests the NULL and empty string
+ */
+static int IpOptsTestParse05(void)
+{
+ DetectIpOptsData *de = DetectIpOptsParse("");
+ FAIL_IF_NOT_NULL(de);
+
+ de = DetectIpOptsParse(NULL);
+ FAIL_IF_NOT_NULL(de);
+
+ PASS;
+}
+
+/**
* \brief this function registers unit tests for IpOpts
*/
void IpOptsRegisterTests(void)
@@ -389,5 +375,6 @@ void IpOptsRegisterTests(void)
UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02);
UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03);
UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04);
+ UtRegisterTest("IpOptsTestParse05", IpOptsTestParse05);
}
#endif /* UNITTESTS */
diff --git a/src/detect-parse.c b/src/detect-parse.c
index c3232b9..5dee7e6 100644
--- a/src/detect-parse.c
+++ b/src/detect-parse.c
@@ -2701,7 +2701,7 @@ int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match,
*match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
if (*match)
return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
- *match, NULL);
+ *match, parse_regex->context);
return -1;
}
@@ -2761,8 +2761,16 @@ bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect
parse_str, en, errbuffer);
return false;
}
- detect_parse->match = pcre2_match_data_create_from_pattern(detect_parse->regex, NULL);
+ detect_parse->context = pcre2_match_context_create(NULL);
+ if (detect_parse->context == NULL) {
+ SCLogError("pcre2 could not create match context");
+ pcre2_code_free(detect_parse->regex);
+ detect_parse->regex = NULL;
+ return false;
+ }
+ pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
+ pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
DetectParseRegexAddToFreeList(detect_parse);
return true;
diff --git a/src/flow-timeout.c b/src/flow-timeout.c
index e5d2794..6efa382 100644
--- a/src/flow-timeout.c
+++ b/src/flow-timeout.c
@@ -341,14 +341,20 @@ int FlowForceReassemblyNeedReassembly(Flow *f)
*
* The function requires flow to be locked beforehand.
*
+ * Normally, the first thread_id value should be used. This is when the flow is
+ * created on seeing the first packet to the server; when the flow's reversed
+ * flag is set, choose the second thread_id (to client/source).
+ *
* \param f Pointer to the flow.
*
* \retval 0 This flow doesn't need any reassembly processing; 1 otherwise.
*/
void FlowForceReassemblyForFlow(Flow *f)
{
- const int thread_id = (int)f->thread_id[0];
- TmThreadsInjectFlowById(f, thread_id);
+ // Choose the thread_id based on whether the flow has been
+ // reversed.
+ int idx = f->flags & FLOW_DIR_REVERSED ? 1 : 0;
+ TmThreadsInjectFlowById(f, (const int)f->thread_id[idx]);
}
/**
diff --git a/src/flow.c b/src/flow.c
index 9783b78..b61823e 100644
--- a/src/flow.c
+++ b/src/flow.c
@@ -291,6 +291,8 @@ void FlowSwap(Flow *f)
FlowSwapFlags(f);
FlowSwapFileFlags(f);
+ SWAP_VARS(FlowThreadId, f->thread_id[0], f->thread_id[1]);
+
if (f->proto == IPPROTO_TCP) {
TcpStreamFlowSwap(f);
}
diff --git a/src/output-json-stats.c b/src/output-json-stats.c
index 33f98af..7cc8807 100644
--- a/src/output-json-stats.c
+++ b/src/output-json-stats.c
@@ -265,23 +265,30 @@ json_t *StatsToJSON(const StatsTable *st, uint8_t flags)
uint32_t x;
for (x = 0; x < st->ntstats; x++) {
uint32_t offset = x * st->nstats;
-
- // Stats for for this thread.
- json_t *thread = json_object();
- if (unlikely(thread == NULL)) {
- json_decref(js_stats);
- json_decref(threads);
- return NULL;
- }
+ const char *tm_name = NULL;
+ json_t *thread = NULL;
/* for each counter */
for (u = offset; u < (offset + st->nstats); u++) {
if (st->tstats[u].name == NULL)
continue;
- // Seems this holds, but assert in debug builds.
- DEBUG_VALIDATE_BUG_ON(
- strcmp(st->tstats[offset].tm_name, st->tstats[u].tm_name) != 0);
+ DEBUG_VALIDATE_BUG_ON(st->tstats[u].tm_name == NULL);
+
+ if (tm_name == NULL) {
+ // First time we see a set tm_name. Remember it
+ // and allocate the stats object for this thread.
+ tm_name = st->tstats[u].tm_name;
+ thread = json_object();
+ if (unlikely(thread == NULL)) {
+ json_decref(js_stats);
+ json_decref(threads);
+ return NULL;
+ }
+ } else {
+ DEBUG_VALIDATE_BUG_ON(strcmp(tm_name, st->tstats[u].tm_name) != 0);
+ DEBUG_VALIDATE_BUG_ON(thread == NULL);
+ }
json_t *js_type = NULL;
const char *stat_name = st->tstats[u].short_name;
@@ -303,7 +310,10 @@ json_t *StatsToJSON(const StatsTable *st, uint8_t flags)
}
}
}
- json_object_set_new(threads, st->tstats[offset].tm_name, thread);
+ if (tm_name != NULL) {
+ DEBUG_VALIDATE_BUG_ON(thread == NULL);
+ json_object_set_new(threads, tm_name, thread);
+ }
}
json_object_set_new(js_stats, "threads", threads);
}
diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c
index b8ad0bf..742d968 100644
--- a/src/runmode-af-packet.c
+++ b/src/runmode-af-packet.c
@@ -90,7 +90,6 @@ static int AFPRunModeIsIPS(void)
SCLogError("Problem with config file");
return 0;
}
- const char *copymodestr = NULL;
if_root = ConfFindDeviceConfig(af_packet_node, live_dev);
if (if_root == NULL) {
@@ -101,7 +100,10 @@ static int AFPRunModeIsIPS(void)
if_root = if_default;
}
- if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
+ const char *copymodestr = NULL;
+ const char *copyifacestr = NULL;
+ if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1 &&
+ ConfGetChildValue(if_root, "copy-iface", &copyifacestr) == 1) {
if (strcmp(copymodestr, "ips") == 0) {
has_ips = 1;
} else {
diff --git a/src/runmode-dpdk.c b/src/runmode-dpdk.c
index 1a240aa..fb49d6e 100644
--- a/src/runmode-dpdk.c
+++ b/src/runmode-dpdk.c
@@ -54,9 +54,12 @@
#define RSS_HKEY_LEN 40
// General purpose RSS key for symmetric bidirectional flow distribution
-uint8_t rss_hkey[] = { 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D,
- 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D,
- 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A };
+uint8_t rss_hkey[] = {
+ 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
+ 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
+ 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, // 40
+ 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, // 52
+};
// Calculates the closest multiple of y from x
#define ROUNDUP(x, y) ((((x) + ((y)-1)) / (y)) * (y))
@@ -111,6 +114,7 @@ static void *ParseDpdkConfigAndConfigureDevice(const char *iface);
static void DPDKDerefConfig(void *conf);
#define DPDK_CONFIG_DEFAULT_THREADS "auto"
+#define DPDK_CONFIG_DEFAULT_INTERRUPT_MODE false
#define DPDK_CONFIG_DEFAULT_MEMPOOL_SIZE 65535
#define DPDK_CONFIG_DEFAULT_MEMPOOL_CACHE_SIZE "auto"
#define DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS 1024
@@ -126,6 +130,7 @@ static void DPDKDerefConfig(void *conf);
DPDKIfaceConfigAttributes dpdk_yaml = {
.threads = "threads",
+ .irq_mode = "interrupt-mode",
.promisc = "promisc",
.multicast = "multicast",
.checksum_checks = "checksum-checks",
@@ -434,6 +439,15 @@ static int ConfigSetThreads(DPDKIfaceConfig *iconf, const char *entry_str)
SCReturnInt(0);
}
+static bool ConfigSetInterruptMode(DPDKIfaceConfig *iconf, bool enable)
+{
+ SCEnter();
+ if (enable)
+ iconf->flags |= DPDK_IRQ_MODE;
+
+ SCReturnBool(true);
+}
+
static int ConfigSetRxQueues(DPDKIfaceConfig *iconf, uint16_t nb_queues)
{
SCEnter();
@@ -704,6 +718,17 @@ static int ConfigLoad(DPDKIfaceConfig *iconf, const char *iface)
if (retval < 0)
SCReturnInt(retval);
+ bool irq_enable;
+ retval = ConfGetChildValueBoolWithDefault(if_root, if_default, dpdk_yaml.irq_mode, &entry_bool);
+ if (retval != 1) {
+ irq_enable = DPDK_CONFIG_DEFAULT_INTERRUPT_MODE;
+ } else {
+ irq_enable = entry_bool ? true : false;
+ }
+ retval = ConfigSetInterruptMode(iconf, irq_enable);
+ if (retval != true)
+ SCReturnInt(-EINVAL);
+
// currently only mapping "1 thread == 1 RX (and 1 TX queue in IPS mode)" is supported
retval = ConfigSetRxQueues(iconf, (uint16_t)iconf->threads);
if (retval < 0)
@@ -846,7 +871,7 @@ static void DeviceSetPMDSpecificRSS(struct rte_eth_rss_conf *rss_conf, const cha
if (strcmp(driver_name, "net_i40e") == 0)
i40eDeviceSetRSSConf(rss_conf);
if (strcmp(driver_name, "net_ice") == 0)
- iceDeviceSetRSSHashFunction(&rss_conf->rss_hf);
+ iceDeviceSetRSSConf(rss_conf);
if (strcmp(driver_name, "net_ixgbe") == 0)
ixgbeDeviceSetRSSHashFunction(&rss_conf->rss_hf);
if (strcmp(driver_name, "net_e1000_igb") == 0)
@@ -1115,6 +1140,11 @@ static void DeviceInitPortConf(const DPDKIfaceConfig *iconf,
},
};
+ SCLogConfig("%s: interrupt mode is %s", iconf->iface,
+ iconf->flags & DPDK_IRQ_MODE ? "enabled" : "disabled");
+ if (iconf->flags & DPDK_IRQ_MODE)
+ port_conf->intr_conf.rxq = 1;
+
// configure RX offloads
if (dev_info->rx_offload_capa & RTE_ETH_RX_OFFLOAD_RSS_HASH) {
if (iconf->nb_rx_queues > 1) {
@@ -1616,7 +1646,9 @@ static int DPDKRunModeIsIPS(void)
}
const char *copymodestr = NULL;
- if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
+ const char *copyifacestr = NULL;
+ if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1 &&
+ ConfGetChildValue(if_root, "copy-iface", &copyifacestr) == 1) {
if (strcmp(copymodestr, "ips") == 0) {
has_ips = true;
} else {
diff --git a/src/runmode-dpdk.h b/src/runmode-dpdk.h
index a00327b..152c1d6 100644
--- a/src/runmode-dpdk.h
+++ b/src/runmode-dpdk.h
@@ -25,6 +25,7 @@
typedef struct DPDKIfaceConfigAttributes_ {
const char *threads;
+ const char *irq_mode;
const char *promisc;
const char *multicast;
const char *checksum_checks;
diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c
index e207cf0..947b381 100644
--- a/src/runmode-netmap.c
+++ b/src/runmode-netmap.c
@@ -81,7 +81,6 @@ static int NetmapRunModeIsIPS(void)
SCLogError("Problem with config file");
return 0;
}
- const char *copymodestr = NULL;
if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev);
if (if_root == NULL) {
@@ -92,7 +91,10 @@ static int NetmapRunModeIsIPS(void)
if_root = if_default;
}
- if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
+ const char *copymodestr = NULL;
+ const char *copyifacestr = NULL;
+ if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1 &&
+ ConfGetChildValue(if_root, "copy-iface", &copyifacestr) == 1) {
if (strcmp(copymodestr, "ips") == 0) {
has_ips = 1;
} else {
diff --git a/src/runmodes.c b/src/runmodes.c
index 348adfa..d4b57df 100644
--- a/src/runmodes.c
+++ b/src/runmodes.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2022 Open Information Security Foundation
+/* Copyright (C) 2007-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@@ -70,6 +70,7 @@
#include "counters.h"
#include "suricata-plugin.h"
+#include "util-device.h"
int debuglog_enabled = 0;
int threading_set_cpu_affinity = FALSE;
@@ -408,6 +409,14 @@ void RunModeEngineIsIPS(int capture_mode, const char *runmode, const char *captu
if (mode->RunModeIsIPSEnabled != NULL) {
mode->RunModeIsIPSEnabled();
+
+ if (EngineModeIsIPS()) {
+ extern uint16_t g_livedev_mask;
+ if (g_livedev_mask != 0 && LiveGetDeviceCount() > 0) {
+ SCLogWarning("disabling livedev.use-for-tracking with IPS mode. See ticket #6726.");
+ g_livedev_mask = 0;
+ }
+ }
}
}
diff --git a/src/source-dpdk.c b/src/source-dpdk.c
index cf26af5..6a7833e 100644
--- a/src/source-dpdk.c
+++ b/src/source-dpdk.c
@@ -93,6 +93,13 @@ TmEcode NoDPDKSupportExit(ThreadVars *tv, const void *initdata, void **data)
#define BURST_SIZE 32
static struct timeval machine_start_time = { 0, 0 };
+// interrupt mode constants
+#define MIN_ZERO_POLL_COUNT 10U
+#define MIN_ZERO_POLL_COUNT_TO_SLEEP 10U
+#define MINIMUM_SLEEP_TIME_US 1U
+#define STANDARD_SLEEP_TIME_US 100U
+#define MAX_EPOLL_TIMEOUT_MS 500U
+static rte_spinlock_t intr_lock[RTE_MAX_ETHPORTS];
/**
* \brief Structure to hold thread specific variables.
@@ -104,6 +111,7 @@ typedef struct DPDKThreadVars_ {
TmSlot *slot;
LiveDevice *livedev;
ChecksumValidationMode checksum_mode;
+ bool intr_enabled;
/* references to packet and drop counters */
uint16_t capture_dpdk_packets;
uint16_t capture_dpdk_rx_errs;
@@ -142,6 +150,40 @@ static uint64_t CyclesToSeconds(uint64_t cycles);
static void DPDKFreeMbufArray(struct rte_mbuf **mbuf_array, uint16_t mbuf_cnt, uint16_t offset);
static uint64_t DPDKGetSeconds(void);
+static bool InterruptsRXEnable(uint16_t port_id, uint16_t queue_id)
+{
+ uint32_t event_data = port_id << UINT16_WIDTH | queue_id;
+ int32_t ret = rte_eth_dev_rx_intr_ctl_q(port_id, queue_id, RTE_EPOLL_PER_THREAD,
+ RTE_INTR_EVENT_ADD, (void *)((uintptr_t)event_data));
+
+ if (ret != 0) {
+ SCLogError("%s-Q%d: failed to enable interrupt mode: %s", DPDKGetPortNameByPortID(port_id),
+ queue_id, rte_strerror(-ret));
+ return false;
+ }
+ return true;
+}
+
+static inline uint32_t InterruptsSleepHeuristic(uint32_t no_pkt_polls_count)
+{
+ if (no_pkt_polls_count < MIN_ZERO_POLL_COUNT_TO_SLEEP)
+ return MINIMUM_SLEEP_TIME_US;
+
+ return STANDARD_SLEEP_TIME_US;
+}
+
+static inline void InterruptsTurnOnOff(uint16_t port_id, uint16_t queue_id, bool on)
+{
+ rte_spinlock_lock(&(intr_lock[port_id]));
+
+ if (on)
+ rte_eth_dev_rx_intr_enable(port_id, queue_id);
+ else
+ rte_eth_dev_rx_intr_disable(port_id, queue_id);
+
+ rte_spinlock_unlock(&(intr_lock[port_id]));
+}
+
static void DPDKFreeMbufArray(struct rte_mbuf **mbuf_array, uint16_t mbuf_cnt, uint16_t offset)
{
for (int i = offset; i < mbuf_cnt; i++) {
@@ -377,6 +419,11 @@ static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot)
rte_eth_stats_reset(ptv->port_id);
rte_eth_xstats_reset(ptv->port_id);
+
+ uint32_t pwd_zero_rx_packet_polls_count = 0;
+ if (ptv->intr_enabled && !InterruptsRXEnable(ptv->port_id, ptv->queue_id))
+ SCReturnInt(TM_ECODE_FAILED);
+
while (1) {
if (unlikely(suricata_ctl_flags != 0)) {
SCLogDebug("Stopping Suricata!");
@@ -398,7 +445,27 @@ static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot)
TmThreadsCaptureHandleTimeout(tv, NULL);
last_timeout_msec = msecs;
}
- continue;
+
+ if (!ptv->intr_enabled)
+ continue;
+
+ pwd_zero_rx_packet_polls_count++;
+ if (pwd_zero_rx_packet_polls_count <= MIN_ZERO_POLL_COUNT)
+ continue;
+
+ uint32_t pwd_idle_hint = InterruptsSleepHeuristic(pwd_zero_rx_packet_polls_count);
+
+ if (pwd_idle_hint < STANDARD_SLEEP_TIME_US) {
+ rte_delay_us(pwd_idle_hint);
+ } else {
+ InterruptsTurnOnOff(ptv->port_id, ptv->queue_id, true);
+ struct rte_epoll_event event;
+ rte_epoll_wait(RTE_EPOLL_PER_THREAD, &event, 1, MAX_EPOLL_TIMEOUT_MS);
+ InterruptsTurnOnOff(ptv->port_id, ptv->queue_id, false);
+ continue;
+ }
+ } else if (ptv->intr_enabled && pwd_zero_rx_packet_polls_count) {
+ pwd_zero_rx_packet_polls_count = 0;
}
ptv->pkts += (uint64_t)nb_rx;
@@ -522,6 +589,7 @@ static TmEcode ReceiveDPDKThreadInit(ThreadVars *tv, const void *initdata, void
ptv->checksum_mode = dpdk_config->checksum_mode;
ptv->threads = dpdk_config->threads;
+ ptv->intr_enabled = (dpdk_config->flags & DPDK_IRQ_MODE) ? true : false;
ptv->port_id = dpdk_config->port_id;
ptv->out_port_id = dpdk_config->out_port_id;
ptv->port_socket_id = dpdk_config->socket_id;
@@ -569,6 +637,9 @@ static TmEcode ReceiveDPDKThreadInit(ThreadVars *tv, const void *initdata, void
"%s: unable to determine NIC's NUMA node, degraded performance can be expected",
dpdk_config->iface);
}
+ if (ptv->intr_enabled) {
+ rte_spinlock_init(&intr_lock[ptv->port_id]);
+ }
}
*data = (void *)ptv;
diff --git a/src/source-dpdk.h b/src/source-dpdk.h
index 3fdb63c..b962d86 100644
--- a/src/source-dpdk.h
+++ b/src/source-dpdk.h
@@ -38,6 +38,7 @@ typedef enum { DPDK_COPY_MODE_NONE, DPDK_COPY_MODE_TAP, DPDK_COPY_MODE_IPS } Dpd
// General flags
#define DPDK_PROMISC (1 << 0) /**< Promiscuous mode */
#define DPDK_MULTICAST (1 << 1) /**< Enable multicast packets */
+#define DPDK_IRQ_MODE (1 << 2) /**< Interrupt mode */
// Offloads
#define DPDK_RX_CHECKSUM_OFFLOAD (1 << 4) /**< Enable chsum offload */
diff --git a/src/source-pcap-file-helper.c b/src/source-pcap-file-helper.c
index 936b65f..4984a44 100644
--- a/src/source-pcap-file-helper.c
+++ b/src/source-pcap-file-helper.c
@@ -251,6 +251,7 @@ TmEcode ValidateLinkType(int datalink, DecoderFunc *DecoderFn)
*DecoderFn = DecodePPP;
break;
case LINKTYPE_IPV4:
+ case LINKTYPE_IPV6:
case LINKTYPE_RAW:
case LINKTYPE_RAW2:
case LINKTYPE_GRE_OVER_IP:
diff --git a/src/tests/detect-http-client-body.c b/src/tests/detect-http-client-body.c
index c87d667..bbeb4d3 100644
--- a/src/tests/detect-http-client-body.c
+++ b/src/tests/detect-http-client-body.c
@@ -157,6 +157,7 @@ static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml)
int i = 0;
while (b->input != NULL) {
SCLogDebug("chunk %p %d", b, i);
+ (void)i;
Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FAIL_IF_NULL(p);
p->flow = &f;
diff --git a/src/tests/detect-http-server-body.c b/src/tests/detect-http-server-body.c
index 29340fb..d9723d4 100644
--- a/src/tests/detect-http-server-body.c
+++ b/src/tests/detect-http-server-body.c
@@ -119,6 +119,7 @@ static int RunTest(struct TestSteps *steps, const char *sig, const char *yaml)
int i = 0;
while (b->input != NULL) {
SCLogDebug("chunk %p %d", b, i);
+ (void)i;
Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FAIL_IF_NULL(p);
p->flow = &f;
diff --git a/src/tests/output-json-stats.c b/src/tests/output-json-stats.c
index ac1336e..332a819 100644
--- a/src/tests/output-json-stats.c
+++ b/src/tests/output-json-stats.c
@@ -23,7 +23,7 @@
static int OutputJsonStatsTest01(void)
{
- StatsRecord global_records[] = { { 0 }, { 0 } };
+ StatsRecord total_records[] = { { 0 }, { 0 } };
StatsRecord thread_records[2];
thread_records[0].name = "capture.kernel_packets";
thread_records[0].short_name = "kernel_packets";
@@ -36,7 +36,7 @@ static int OutputJsonStatsTest01(void)
StatsTable table = {
.nstats = 2,
- .stats = &global_records[0],
+ .stats = &total_records[0],
.ntstats = 1,
.tstats = &thread_records[0],
};
@@ -64,7 +64,72 @@ static int OutputJsonStatsTest01(void)
return cmp_result == 0;
}
+static int OutputJsonStatsTest02(void)
+{
+ StatsRecord total_records[4] = { 0 };
+ StatsRecord thread_records[8] = { 0 };
+
+ // Totals
+ total_records[0].name = "tcp.syn";
+ total_records[0].short_name = "syn";
+ total_records[0].tm_name = NULL;
+ total_records[0].value = 1234;
+
+ // Worker
+ // thread_records[0] is a global counter
+ thread_records[1].name = "capture.kernel_packets";
+ thread_records[1].short_name = "kernel_packets";
+ thread_records[1].tm_name = "W#01-bond0.30";
+ thread_records[1].value = 42;
+ thread_records[2].name = "capture.kernel_drops";
+ thread_records[2].short_name = "kernel_drops";
+ thread_records[2].tm_name = "W#01-bond0.30";
+ thread_records[2].value = 4711;
+ // thread_records[3] is a FM specific counter
+
+ // Flow manager
+ // thread_records[4] is a global counter
+ // thread_records[5] is a worker specific counter
+ // thread_records[6] is a worker specific counter
+ thread_records[7].name = "flow.mgr.full_hash_passes";
+ thread_records[7].short_name = "full_hash_passes";
+ thread_records[7].tm_name = "FM#01";
+ thread_records[7].value = 10;
+
+ StatsTable table = {
+ .nstats = 4,
+ .stats = &total_records[0],
+ .ntstats = 2,
+ .tstats = &thread_records[0],
+ };
+
+ json_t *r = StatsToJSON(&table, JSON_STATS_TOTALS | JSON_STATS_THREADS);
+ if (!r)
+ return 0;
+
+ // Remove variable content
+ json_object_del(r, "uptime");
+
+ char *serialized = json_dumps(r, 0);
+
+ // Cheesy comparison
+ const char *expected = "{\"tcp\": {\"syn\": 1234}, \"threads\": {\"W#01-bond0.30\": "
+ "{\"capture\": {\"kernel_packets\": "
+ "42, \"kernel_drops\": 4711}}, \"FM#01\": {\"flow\": {\"mgr\": "
+ "{\"full_hash_passes\": 10}}}}}";
+
+ int cmp_result = strcmp(expected, serialized);
+ if (cmp_result != 0)
+ printf("unexpected result\nexpected=%s\ngot=%s\n", expected, serialized);
+
+ free(serialized);
+ json_decref(r);
+
+ return cmp_result == 0;
+}
+
void OutputJsonStatsRegisterTests(void)
{
UtRegisterTest("OutputJsonStatsTest01", OutputJsonStatsTest01);
+ UtRegisterTest("OutputJsonStatsTest02", OutputJsonStatsTest02);
}
diff --git a/src/util-base64.c b/src/util-base64.c
index 4a4a5d1..d973f0e 100644
--- a/src/util-base64.c
+++ b/src/util-base64.c
@@ -156,6 +156,8 @@ Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src,
ecode = BASE64_ECODE_BUF;
break;
}
+ if (dest_size - *decoded_bytes < ASCII_BLOCK)
+ return BASE64_ECODE_BUF;
/* Decode base-64 block into ascii block and move pointer */
DecodeBase64Block(dptr, b64);
@@ -183,7 +185,7 @@ Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src,
/* if the destination size is not at least 3 Bytes long, it'll give a dynamic
* buffer overflow while decoding, so, return and let the caller take care of the
* remaining bytes to be decoded which should always be < 4 at this stage */
- if (dest_size - *decoded_bytes < 3)
+ if (dest_size - *decoded_bytes < ASCII_BLOCK)
return BASE64_ECODE_BUF;
*decoded_bytes += numDecoded_blk;
DecodeBase64Block(dptr, b64);
@@ -193,6 +195,8 @@ Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src,
/* Finish remaining b64 bytes by padding */
if (valid && bbidx > 0 && (mode != BASE64_MODE_RFC2045)) {
/* Decode remaining */
+ if (dest_size - *decoded_bytes < ASCII_BLOCK)
+ return BASE64_ECODE_BUF;
*decoded_bytes += ASCII_BLOCK - (B64_BLOCK - bbidx);
DecodeBase64Block(dptr, b64);
}
diff --git a/src/util-dpdk-ice.c b/src/util-dpdk-ice.c
index 36f4481..4b714d8 100644
--- a/src/util-dpdk-ice.c
+++ b/src/util-dpdk-ice.c
@@ -35,7 +35,7 @@
#ifdef HAVE_DPDK
-void iceDeviceSetRSSHashFunction(uint64_t *rss_hf)
+static void iceDeviceSetRSSHashFunction(uint64_t *rss_hf)
{
#if RTE_VERSION < RTE_VERSION_NUM(20, 0, 0, 0)
*rss_hf = RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | RTE_ETH_RSS_FRAG_IPV6 |
@@ -46,6 +46,16 @@ void iceDeviceSetRSSHashFunction(uint64_t *rss_hf)
#endif
}
+void iceDeviceSetRSSConf(struct rte_eth_rss_conf *rss_conf)
+{
+ iceDeviceSetRSSHashFunction(&rss_conf->rss_hf);
+#if RTE_VERSION < RTE_VERSION_NUM(23, 11, 0, 0)
+ rss_conf->rss_key_len = 40;
+#else
+ rss_conf->rss_key_len = 52;
+#endif
+}
+
#endif /* HAVE_DPDK */
/**
* @}
diff --git a/src/util-dpdk-ice.h b/src/util-dpdk-ice.h
index cdc2185..d535fa0 100644
--- a/src/util-dpdk-ice.h
+++ b/src/util-dpdk-ice.h
@@ -28,7 +28,9 @@
#ifdef HAVE_DPDK
-void iceDeviceSetRSSHashFunction(uint64_t *rss_conf);
+#include "util-dpdk.h"
+
+void iceDeviceSetRSSConf(struct rte_eth_rss_conf *rss_conf);
#endif /* HAVE_DPDK */
diff --git a/src/util-host-info.c b/src/util-host-info.c
index c0dd93b..282b2fb 100644
--- a/src/util-host-info.c
+++ b/src/util-host-info.c
@@ -44,7 +44,6 @@ int SCKernelVersionIsAtLeast(int major, int minor)
PCRE2_SIZE eo;
int ret;
int kmajor, kminor;
- PCRE2_UCHAR **list;
/* get local version */
if (uname(&kuname) != 0) {
@@ -79,25 +78,36 @@ int SCKernelVersionIsAtLeast(int major, int minor)
goto error;
}
- pcre2_substring_list_get(version_regex_match, &list, NULL);
+ char majorstr[32];
+ size_t pcre2len = sizeof(majorstr);
+ ret = pcre2_substring_copy_bynumber(
+ version_regex_match, 1, (PCRE2_UCHAR8 *)majorstr, &pcre2len);
+ if (ret < 0) {
+ SCLogError("pcre2_substring_copy_bynumber failed");
+ goto error;
+ }
- bool err = false;
- if (StringParseInt32(&kmajor, 10, 0, (const char *)list[1]) < 0) {
- SCLogError("Invalid value for kmajor: '%s'", list[1]);
- err = true;
+ char minorstr[32];
+ pcre2len = sizeof(majorstr);
+ ret = pcre2_substring_copy_bynumber(
+ version_regex_match, 2, (PCRE2_UCHAR8 *)minorstr, &pcre2len);
+ if (ret < 0) {
+ SCLogError("pcre2_substring_copy_bynumber failed");
+ goto error;
}
- if (StringParseInt32(&kminor, 10, 0, (const char *)list[2]) < 0) {
- SCLogError("Invalid value for kminor: '%s'", list[2]);
- err = true;
+
+ if (StringParseInt32(&kmajor, 10, 0, (const char *)majorstr) < 0) {
+ SCLogError("Invalid value for kmajor: '%s'", minorstr);
+ goto error;
+ }
+ if (StringParseInt32(&kminor, 10, 0, (const char *)minorstr) < 0) {
+ SCLogError("Invalid value for kminor: '%s'", minorstr);
+ goto error;
}
- pcre2_substring_list_free((PCRE2_SPTR *)list);
pcre2_match_data_free(version_regex_match);
pcre2_code_free(version_regex);
- if (err)
- goto error;
-
if (kmajor > major)
return 1;
if (kmajor == major && kminor >= minor)
diff --git a/src/util-streaming-buffer.c b/src/util-streaming-buffer.c
index 6ff4f43..204ef2e 100644
--- a/src/util-streaming-buffer.c
+++ b/src/util-streaming-buffer.c
@@ -1064,7 +1064,15 @@ void StreamingBufferSlideToOffset(
DEBUG_VALIDATE_BUG_ON(sb->region.stream_offset < offset);
}
-#define DATA_FITS(sb, len) ((sb)->region.buf_offset + (len) <= (sb)->region.buf_size)
+static int DataFits(const StreamingBuffer *sb, const uint32_t len)
+{
+ uint64_t buf_offset64 = sb->region.buf_offset;
+ uint64_t len64 = len;
+ if (len64 + buf_offset64 > UINT32_MAX) {
+ return -1;
+ }
+ return sb->region.buf_offset + len <= sb->region.buf_size;
+}
int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len)
@@ -1076,7 +1084,11 @@ int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
return -1;
}
- if (!DATA_FITS(sb, data_len)) {
+ int r = DataFits(sb, data_len);
+ if (r < 0) {
+ DEBUG_VALIDATE_BUG_ON(1);
+ return -1;
+ } else if (r == 0) {
if (sb->region.buf_size == 0) {
if (GrowToSize(sb, cfg, data_len) != SC_OK)
return -1;
@@ -1085,7 +1097,7 @@ int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
return -1;
}
}
- DEBUG_VALIDATE_BUG_ON(!DATA_FITS(sb, data_len));
+ DEBUG_VALIDATE_BUG_ON(DataFits(sb, data_len) != 1);
memcpy(sb->region.buf + sb->region.buf_offset, data, data_len);
seg->stream_offset = sb->region.stream_offset + sb->region.buf_offset;
@@ -1111,7 +1123,11 @@ int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfi
return -1;
}
- if (!DATA_FITS(sb, data_len)) {
+ int r = DataFits(sb, data_len);
+ if (r < 0) {
+ DEBUG_VALIDATE_BUG_ON(1);
+ return -1;
+ } else if (r == 0) {
if (sb->region.buf_size == 0) {
if (GrowToSize(sb, cfg, data_len) != SC_OK)
return -1;
@@ -1120,7 +1136,7 @@ int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfi
return -1;
}
}
- DEBUG_VALIDATE_BUG_ON(!DATA_FITS(sb, data_len));
+ DEBUG_VALIDATE_BUG_ON(DataFits(sb, data_len) != 1);
memcpy(sb->region.buf + sb->region.buf_offset, data, data_len);
uint32_t rel_offset = sb->region.buf_offset;
@@ -1133,7 +1149,15 @@ int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfi
}
}
-#define DATA_FITS_AT_OFFSET(region, len, offset) ((offset) + (len) <= (region)->buf_size)
+static int DataFitsAtOffset(
+ const StreamingBufferRegion *region, const uint32_t len, const uint32_t offset)
+{
+ const uint64_t offset64 = offset;
+ const uint64_t len64 = len;
+ if (offset64 + len64 > UINT32_MAX)
+ return -1;
+ return (offset + len <= region->buf_size);
+}
#if defined(DEBUG) || defined(DEBUG_VALIDATION)
static void Validate(const StreamingBuffer *sb)
@@ -1477,8 +1501,6 @@ static StreamingBufferRegion *BufferInsertAtRegion(StreamingBuffer *sb,
int StreamingBufferInsertAt(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len, uint64_t offset)
{
- int r;
-
DEBUG_VALIDATE_BUG_ON(seg == NULL);
DEBUG_VALIDATE_BUG_ON(offset < sb->region.stream_offset);
if (offset < sb->region.stream_offset) {
@@ -1496,11 +1518,15 @@ int StreamingBufferInsertAt(StreamingBuffer *sb, const StreamingBufferConfig *cf
region == &sb->region ? "main" : "aux", region);
uint32_t rel_offset = offset - region->stream_offset;
- if (!DATA_FITS_AT_OFFSET(region, data_len, rel_offset)) {
+ int r = DataFitsAtOffset(region, data_len, rel_offset);
+ if (r < 0) {
+ DEBUG_VALIDATE_BUG_ON(1);
+ return SC_ELIMIT;
+ } else if (r == 0) {
if ((r = GrowToSize(sb, cfg, (rel_offset + data_len))) != SC_OK)
return r;
}
- DEBUG_VALIDATE_BUG_ON(!DATA_FITS_AT_OFFSET(region, data_len, rel_offset));
+ DEBUG_VALIDATE_BUG_ON(DataFitsAtOffset(region, data_len, rel_offset) != 1);
SCLogDebug("offset %" PRIu64 " data_len %u, rel_offset %u into region offset %" PRIu64
", buf_offset %u, buf_size %u",
@@ -2320,6 +2346,22 @@ static int StreamingBufferTest10(void)
PASS;
}
+static int StreamingBufferTest11(void)
+{
+ StreamingBufferConfig cfg = { 24, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
+ StreamingBuffer *sb = StreamingBufferInit(&cfg);
+ FAIL_IF(sb == NULL);
+
+ StreamingBufferSegment seg1;
+ FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
+ StreamingBufferSegment seg2;
+ unsigned int data_len = 0xffffffff;
+ FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg2, (const uint8_t *)"unused", data_len) != -1);
+ FAIL_IF(StreamingBufferInsertAt(
+ sb, &cfg, &seg2, (const uint8_t *)"abcdefghij", data_len, 100000) != SC_ELIMIT);
+ StreamingBufferFree(sb, &cfg);
+ PASS;
+}
#endif
void StreamingBufferRegisterTests(void)
@@ -2333,5 +2375,6 @@ void StreamingBufferRegisterTests(void)
UtRegisterTest("StreamingBufferTest08", StreamingBufferTest08);
UtRegisterTest("StreamingBufferTest09", StreamingBufferTest09);
UtRegisterTest("StreamingBufferTest10", StreamingBufferTest10);
+ UtRegisterTest("StreamingBufferTest11 Bug 6903", StreamingBufferTest11);
#endif
}
diff --git a/suricata-update/CHANGELOG.md b/suricata-update/CHANGELOG.md
index 03310ca..6ae15ec 100644
--- a/suricata-update/CHANGELOG.md
+++ b/suricata-update/CHANGELOG.md
@@ -1,5 +1,9 @@
# Change Log
+## 1.3.3 - 2024-04-16
+- Add missing engine provided rules:
+ https://redmine.openinfosecfoundation.org/issues/6932
+
## 1.3.2 - 2024-03-14
- Fix copying of file hash lists which was broken in the dataset fix
as part of ticket #6833:
diff --git a/suricata-update/Makefile b/suricata-update/Makefile
index e0ceb8f..7149893 100644
--- a/suricata-update/Makefile
+++ b/suricata-update/Makefile
@@ -253,10 +253,10 @@ OTOOL64 =
PACKAGE = suricata
PACKAGE_BUGREPORT =
PACKAGE_NAME = suricata
-PACKAGE_STRING = suricata 7.0.4
+PACKAGE_STRING = suricata 7.0.5
PACKAGE_TARNAME = suricata
PACKAGE_URL =
-PACKAGE_VERSION = 7.0.4
+PACKAGE_VERSION = 7.0.5
PATH_SEPARATOR = :
PCAP_CFLAGS = -I/usr/include
PCAP_LIBS = -lpcap
@@ -265,6 +265,7 @@ PKG_CONFIG_LIBDIR =
PKG_CONFIG_PATH =
POW_LIB =
RANLIB = ranlib
+RELEASE_DATE = 2024-04-23
RUSTC = /usr/bin/rustc
RUSTUP_HOME_PATH = no
RUST_FEATURES =
@@ -280,7 +281,7 @@ SHELL = /bin/bash
SPHINX_BUILD = /usr/bin/sphinx-build
STRIP = strip
SURICATA_UPDATE_DIR = suricata-update
-VERSION = 7.0.4
+VERSION = 7.0.5
abs_builddir = /builds/dev/suricata/suricata-update
abs_srcdir = /builds/dev/suricata/suricata-update
abs_top_builddir = /builds/dev/suricata
diff --git a/suricata-update/Makefile.in b/suricata-update/Makefile.in
index 1273803..4b2cc7a 100644
--- a/suricata-update/Makefile.in
+++ b/suricata-update/Makefile.in
@@ -265,6 +265,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/suricata-update/suricata/update/main.py b/suricata-update/suricata/update/main.py
index 18af7a8..7814518 100644
--- a/suricata-update/suricata/update/main.py
+++ b/suricata-update/suricata/update/main.py
@@ -334,14 +334,19 @@ def load_dist_rules(files):
"dnp3-events.rules",
"dns-events.rules",
"files.rules",
+ "http2-events.rules",
"http-events.rules",
"ipsec-events.rules",
"kerberos-events.rules",
"modbus-events.rules",
+ "mqtt-events.rules",
"nfs-events.rules",
"ntp-events.rules",
+ "quic-events.rules",
+ "rfb-events.rules",
"smb-events.rules",
"smtp-events.rules",
+ "ssh-events.rules",
"stream-events.rules",
"tls-events.rules",
]
diff --git a/suricata-update/suricata/update/version.py b/suricata-update/suricata/update/version.py
index 75d1205..d190ec4 100644
--- a/suricata-update/suricata/update/version.py
+++ b/suricata-update/suricata/update/version.py
@@ -4,4 +4,4 @@
# Alpha: 1.0.0a1
# Development: 1.0.0dev0
# Release candidate: 1.0.0rc1
-version = "1.3.2"
+version = "1.3.3"
diff --git a/suricata.yaml.in b/suricata.yaml.in
index b141c08..3ead5f5 100644
--- a/suricata.yaml.in
+++ b/suricata.yaml.in
@@ -753,6 +753,7 @@ dpdk:
# - auto takes all cores
# in IPS mode it is required to specify the number of cores and the numbers on both interfaces must match
threads: auto
+ # interrupt-mode: false # true to switch to interrupt mode
promisc: true # promiscuous mode - capture all packets
multicast: true # enables also detection on multicast packets
checksum-checks: true # if Suricata should validate checksums