diff --git a/.clang-format b/.clang-format index 0b3aa2389..56e516cd6 100644 --- a/.clang-format +++ b/.clang-format @@ -3,10 +3,12 @@ AccessModifierOffset: -4 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: None AlignOperands: Align +AlignTrailingComments: true AllowAllArgumentsOnNextLine: false AllowAllConstructorInitializersOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: Always +AllowShortEnumsOnASingleLine: true AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: None AllowShortLambdasOnASingleLine: All @@ -16,7 +18,7 @@ AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: TopLevelDefinitions AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes -AttributeMacros: ['__capability', '__output', '__ununsed', '_U_'] +AttributeMacros: ['__capability', '__output', '__unused', '_U_'] BinPackArguments: false BinPackParameters: false BitFieldColonSpacing: None @@ -28,9 +30,11 @@ BraceWrapping: AfterEnum: false AfterFunction: true AfterNamespace: false + AfterStruct: false AfterUnion: false BeforeCatch: false BeforeElse: false + BeforeWhile: false IndentBraces: false SplitEmptyFunction: false SplitEmptyRecord: true @@ -69,7 +73,12 @@ IncludeCategories: Priority: 6 IndentGotoLabels: false IndentPPDirectives: None +IndentRequiresClause: false +IndentExternBlock: AfterExternBlock IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: true +InsertTrailingCommas: None KeepEmptyLinesAtTheStartOfBlocks: false MaxEmptyLinesToKeep: 1 NamespaceIndentation: None @@ -86,12 +95,16 @@ SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyBlock: false SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: Never SpacesInConditionalStatement: false SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 SpacesInParentheses: false SpacesInSquareBrackets: false TabWidth: 8 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..5c94caeb5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,20 @@ +## Standards checklist: + + + +- [ ] The PR title is descriptive. +- [ ] The PR doesn't replicate another PR which is already open. +- [ ] I have read the contribution guide and followed all the instructions. +- [ ] The code follows the code style guide detailed in the wiki. +- [ ] The code is mine or it's from somewhere with an MIT-compatible license. +- [ ] The code is efficient, to the best of my ability, and does not waste computer resources. +- [ ] The code is stable and I have tested it myself, to the best of my abilities. +- [ ] If the code introduces new aliases, I provide a valid use case for all plugin users down below. + +## Changes: + +- [...] + +## Other comments: + +... diff --git a/.github/workflows/c-linter.yml b/.github/workflows/c-linter.yml index 30d9293f0..e0395c6ea 100644 --- a/.github/workflows/c-linter.yml +++ b/.github/workflows/c-linter.yml @@ -27,5 +27,8 @@ jobs: if: steps.linter.outputs.checks-failed > 0 # for testing... # run: echo "Some files failed the linting checks!" + # for development... + run: exit 0 # exit the job with a success status # for actual deployment... - run: exit 1 + # run: exit 1 # exit the job with a failure status + diff --git a/.github/workflows/github-actions-ci.yml b/.github/workflows/github-actions-ci.yml index 21b5e2480..1b81f6146 100644 --- a/.github/workflows/github-actions-ci.yml +++ b/.github/workflows/github-actions-ci.yml @@ -18,7 +18,7 @@ jobs: - name: Create configure script run: ./autogen.sh - name: configure - run: ./configure --with-testnic=eth0 --disable-local-libopts + run: ./configure --with-testnic=eth0 --disable-local-libopts --enable-asan - name: make run: make - name: make dist @@ -28,5 +28,5 @@ jobs: - name: List files in the repository run: ls ${{ github.workspace }} - name: tests - run: sudo make test + run: sudo make test || (cat test/test.log; false) - run: echo "This test's status is ${{ job.status }}." diff --git a/INSTALL b/INSTALL deleted file mode 100644 index ae077a6a3..000000000 --- a/INSTALL +++ /dev/null @@ -1,303 +0,0 @@ -Installation Instructions -************************* - -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, -2006, 2014 Free Software Foundation, Inc. - -This file is free documentation; the Free Software Foundation gives -unlimited permission to copy, distribute and modify it. - - -Advanced Installation -===================== -Visit http://tcpreplay.appneta.com/wiki/installation.html - - -Basic Installation -================== - - ./configure - make - sudo make install - -Briefly, the shell commands `./configure; make; make install' should -configure, build, and install this package. The following -more-detailed instructions are generic; see the `README' file for -instructions specific to this package. - - The `configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation. It uses -those values to create a `Makefile' in each directory of the package. -It may also create one or more `.h' files containing system-dependent -definitions. Finally, it creates a shell script `config.status' that -you can run in the future to recreate the current configuration, and a -file `config.log' containing compiler output (useful mainly for -debugging `configure'). - - It can also use an optional file (typically called `config.cache' -and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. Caching is -disabled by default to prevent problems with accidental use of stale -cache files. - - If you need to do unusual things to compile the package, please try -to figure out how `configure' could check whether to do them, and mail -diffs or instructions to the address given in the `README' so they can -be considered for the next release. If you are using the cache, and at -some point `config.cache' contains results you don't want to keep, you -may remove or edit it. - - The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You need `configure.ac' if -you want to change it or regenerate `configure' using a newer version -of `autoconf'. - -The simplest way to compile this package is: - - 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. - - Running `configure' might take a while. While running, it prints - some messages telling which features it is checking for. - - 2. Type `make' to compile the package. - - 3. Optionally, type `make check' to run any self-tests that come with - the package. - - 4. Type `make install' to install the programs and any data files and - documentation. - - 5. You can remove the program binaries and object files from the - source code directory by typing `make clean'. To also remove the - files that `configure' created (so you can compile the package for - a different kind of computer), type `make distclean'. There is - also a `make maintainer-clean' target, but that is intended mainly - for the package's developers. If you use it, you may have to get - all sorts of other programs in order to regenerate files that came - with the distribution. - - -How to make Tcpreplay go fast -============================= - -1) netmap - ------ -This feature will detect netmap capable network drivers on Linux and -BSD systems. If detected, the network driver is bypassed for the -execution duration of tcpreplay and tcpreplay-edit, and network buffers -will be written to directly. This will allow you to achieve full 10GigE -line rates on commodity 10GigE network adapters, similar to rates -achieved by commercial network traffic generators. - -Note that bypassing the network driver will disrupt other applications -connected through the test interface. Use caution when testing on the -same interface you ssh'ed into. - -Ensure that you have supported NICs installed. Most Intel and nForce -(nVidia) adapters will work. Some virtual adapters are supported. - -FreeBSD 10 and higher already contains netmap capabilities and should -be detected automatically by "configure". But first you must enable -netmap on the system by adding 'device netmap' to your kernel config -and rebuilding the kernel. When complete, /dev/netmap will be -available. - -For Linux, download latest netmap sources from http://info.iet.unipi.it/~luigi/netmap/ -or run 'git clone https://code.google.com/p/netmap/'. You will also need to have -kernel sources installed so the build system can patch the sources and build -netmap-enabled drivers. If kernel sources are in /a/b/c/linux-A.B.C/ , then you -should do: - - cd netmap/LINUX - make KSRC=/a/b/c/linux-A.B.C/ # builds the kernel modules - make KSRC=/a/b/c/linux-A.B.C/ apps # builds sample applications - -You can omit KSRC if your kernel sources are in a standard place. - -Once you load the netmap.lin.ko module on your Linux machine, /dev/netmap -will be available. You will also need to replace your existing network drivers -(beyond the scope of this document). - -Building netmap-aware Tcpreplay suite is relatively straight forward. For -FreeBSD, build normally. For Linux, if you extracted netmap into /usr/src/ you -can also build normally. Otherwise you will have to specify the netmap source -directory, for example: - - ./configure --with-netmap=/home/fklassen/git/netmap - make - sudo make install - - -Compilers and Options -===================== - -Some systems require unusual options for compilation or linking that the -`configure' script does not know about. Run `./configure --help' for -details on some of the pertinent environment variables. - - You can give `configure' initial values for configuration parameters -by setting variables in the command line or in the environment. Here -is an example: - - ./configure CC=c99 CFLAGS=-g LIBS=-lposix - - *Note Defining Variables::, for more details. - - -Compiling For Multiple Architectures -==================================== - -You can compile the package for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you can use GNU `make'. `cd' to the -directory where you want the object files and executables to go and run -the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. - - With a non-GNU `make', it is safer to compile the package for one -architecture at a time in the source code directory. After you have -installed the package for one architecture, use `make distclean' before -reconfiguring for another architecture. - - -Installation Names -================== - -By default, `make install' installs the package's commands under -`/usr/local/bin', include files under `/usr/local/include', etc. You -can specify an installation prefix other than `/usr/local' by giving -`configure' the option `--prefix=PREFIX'. - - You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If you -pass the option `--exec-prefix=PREFIX' to `configure', the package uses -PREFIX as the prefix for installing programs and libraries. -Documentation and other data files still use the regular prefix. - - In addition, if you use an unusual directory layout you can give -options like `--bindir=DIR' to specify different values for particular -kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. - - If the package supports it, you can cause programs to be installed -with an extra prefix or suffix on their names by giving `configure' the -option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. - - -Optional Features -================= - -Some packages pay attention to `--enable-FEATURE' options to -`configure', where FEATURE indicates an optional part of the package. -They may also pay attention to `--with-PACKAGE' options, where PACKAGE -is something like `gnu-as' or `x' (for the X Window System). The -`README' should mention any `--enable-' and `--with-' options that the -package recognizes. - - For packages that use the X Window System, `configure' can usually -find the X include and library files automatically, but if it doesn't, -you can use the `configure' options `--x-includes=DIR' and -`--x-libraries=DIR' to specify their locations. - - -Specifying the System Type -========================== - -There may be some features `configure' cannot figure out automatically, -but needs to determine by the type of machine the package will run on. -Usually, assuming the package is built to be run on the _same_ -architectures, `configure' can figure that out, but if it prints a -message saying it cannot guess the machine type, give it the -`--build=TYPE' option. TYPE can either be a short name for the system -type, such as `sun4', or a canonical name which has the form: - - CPU-COMPANY-SYSTEM - -where SYSTEM can have one of these forms: - - OS KERNEL-OS - - See the file `config.sub' for the possible values of each field. If -`config.sub' isn't included in this package, then this package doesn't -need to know the machine type. - - If you are _building_ compiler tools for cross-compiling, you should -use the option `--target=TYPE' to select the type of system they will -produce code for. - - If you want to _use_ a cross compiler, that generates code for a -platform different from the build platform, you should specify the -"host" platform (i.e., that on which the generated programs will -eventually be run) with `--host=TYPE'. - - -Sharing Defaults -================ - -If you want to set default values for `configure' scripts to share, you -can create a site shell script called `config.site' that gives default -values for variables like `CC', `cache_file', and `prefix'. -`configure' looks for `PREFIX/share/config.site' if it exists, then -`PREFIX/etc/config.site' if it exists. Or, you can set the -`CONFIG_SITE' environment variable to the location of the site script. -A warning: not all `configure' scripts look for a site script. - - -Defining Variables -================== - -Variables not defined in a site shell script can be set in the -environment passed to `configure'. However, some packages may run -configure again during the build, and the customized values of these -variables may be lost. In order to avoid this problem, you should set -them in the `configure' command line, using `VAR=value'. For example: - - ./configure CC=/usr/local2/bin/gcc - -causes the specified `gcc' to be used as the C compiler (unless it is -overridden in the site shell script). - -Unfortunately, this technique does not work for `CONFIG_SHELL' due to -an Autoconf bug. Until the bug is fixed you can use this workaround: - - CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash - - -`configure' Invocation -====================== - -`configure' recognizes the following options to control how it operates. - -`--help' -`-h' - Print a summary of the options to `configure', and exit. - -`--version' -`-V' - Print the version of Autoconf used to generate the `configure' - script, and exit. - -`--cache-file=FILE' - Enable the cache: use and save the results of the tests in FILE, - traditionally `config.cache'. FILE defaults to `/dev/null' to - disable caching. - -`--config-cache' -`-C' - Alias for `--cache-file=config.cache'. - -`--quiet' -`--silent' -`-q' - Do not print messages saying which checks are being made. To - suppress all normal output, redirect it to `/dev/null' (any error - messages will still be shown). - -`--srcdir=DIR' - Look for the package's source code in directory DIR. Usually - `configure' can determine that directory automatically. - -`configure' also accepts some other, not widely useful, options. Run -`configure --help' for more details. - diff --git a/configure.ac b/configure.ac index 387219deb..ded653849 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ dnl $Id$ AC_PREREQ([2.69]) dnl Set version info here! -AC_INIT([tcpreplay],[4.4.4],[https://github.com/appneta/tcpreplay/issues],[tcpreplay],[http://tcpreplay.sourceforge.net/]) +AC_INIT([tcpreplay],[4.5.0-beta2],[https://github.com/appneta/tcpreplay/issues],[tcpreplay],[http://tcpreplay.sourceforge.net/]) AC_CONFIG_SRCDIR([src/tcpreplay.c]) AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_AUX_DIR(config) @@ -566,6 +566,10 @@ AC_ARG_ENABLE(force-libdnet, AS_HELP_STRING([--enable-force-libdnet],[Force using libdnet for sending packets]), [ AC_DEFINE([FORCE_INJECT_LIBDNET], [1], [Force using libdnet for sending packets])]) +AC_ARG_ENABLE(force-libxdp, + AS_HELP_STRING([--enable-force-libxdp],[Force using libxdp for sending packets]), + [ AC_DEFINE([FORCE_INJECT_LIBXDP], [1], [Force using libxdp for sending packets])]) + AC_ARG_ENABLE(force-inject, AS_HELP_STRING([--enable-force-inject],[Force using libpcap's pcap_inject() for sending packets]), [ AC_DEFINE([FORCE_INJECT_PCAP_INJECT],[1], [Force using libpcap's pcap_inject() for sending packets])]) @@ -605,32 +609,61 @@ else fi dnl Check for inet_aton and inet_pton +dnl On Haiku these functions are in libnetwork. AC_CHECK_FUNC(inet_aton, AC_DEFINE([HAVE_INET_ATON], [1], [Do we have inet_aton?]) inet_aton=yes, - inet_aton=no) + [ + AC_CHECK_LIB(network, inet_aton, + AC_DEFINE([HAVE_INET_ATON], [1], [Do we have inet_aton?]) + use_libnetwork=yes, + [inet_aton=no] + ) + ] +) AC_CHECK_FUNC(inet_pton, AC_DEFINE([HAVE_INET_PTON], [1], [Do we have inet_pton?]) inet_pton=yes, - inet_pton=no) + [ + AC_CHECK_LIB(network, inet_pton, + AC_DEFINE([HAVE_INET_PTON], [1], [Do we have inet_pton?]) + use_libnetwork=yes, + [inet_pton=no] + ) + ] +) AC_CHECK_FUNC(inet_ntop, AC_DEFINE([HAVE_INET_NTOP], [1], [Do we have inet_ntop?]) inet_ntop=yes, - inet_ntop=no) + [ + AC_CHECK_LIB(network, inet_ntop, + AC_DEFINE([HAVE_INET_NTOP], [1], [Do we have inet_ntop?]) + use_libnetwork=yes, + [inet_ntop=no] + ) + ] +) if test "$inet_ntop" = "no" -a "$inet_pton" = "no" ; then AC_MSG_ERROR([We need either inet_ntop or inet_pton]) fi +if test "$use_libnetwork" = "yes" ; then + LIBS="-lnetwork $LIBS" +fi + AC_CHECK_FUNC(inet_addr, AC_DEFINE([HAVE_INET_ADDR], [1], [Do we have inet_addr?]) inet_addr=yes, inet_addr=no) -if test x$inet_addr = no ; then +if test x$inet_addr = xno ; then AC_MSG_ERROR([We need inet_addr. See bug 26]) fi +dnl On Haiku fts_*() functions are in libbsd. +AC_CHECK_FUNC(fts_read,,[AC_CHECK_LIB(bsd, fts_read)]) + dnl ##################################################### dnl Checks for tuntap device support dnl ##################################################### @@ -671,7 +704,7 @@ AC_ARG_WITH(libpcap, LPCAPINCDIR=${testdir} if test $dynamic_link = yes; then for ext in .dylib .so .tbd ; do - for dir in . lib lib64 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do + for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do sharefile=$(ls ${testdir}/$dir/libpcap${ext}* 2> /dev/null | sort | head -n1) if test -n "${sharefile}"; then LPCAP_LD_LIBRARY_PATH="$(dirname ${sharefile})" @@ -690,7 +723,7 @@ AC_ARG_WITH(libpcap, dnl If dynamic library not found, try static dnl for ext in ${libext} .a .A.tbd ; do - for dir in . lib lib64 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do + for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do staticfile=$(ls ${testdir}/$dir/libpcap${ext} 2> /dev/null | sort | head -n1) if test -n "${staticfile}"; then LPCAPLIB="${staticfile}" @@ -771,7 +804,7 @@ AC_ARG_WITH(libpcap, LPCAPINCDIR="${testdir}/include" if test $dynamic_link = yes; then for ext in .dylib .so .tbd; do - for dir in . lib lib64 ${host_cpu} lib/${host_cpu} ${host_cpu}-${host_os} lib/${host_cpu}-${host_os} ${MULTIARCH} lib/${MULTIARCH}; do + for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do sharefile=$(ls "${testdir}/$dir/libpcap${ext}" 2> /dev/null | sort | head -n1) if test -n "${sharefile}"; then LPCAPLIB="-L$(dirname ${sharefile}) -lpcap" @@ -790,7 +823,7 @@ AC_ARG_WITH(libpcap, dnl If dynamic library not found, try static dnl for ext in ${libext} .a .A.tbd ; do - for dir in . lib lib64 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do + for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do staticfile=$(ls "${testdir}/$dir/libpcap${ext}" 2> /dev/null | sort | head -n1) if test -n "${staticfile}"; then LPCAPLIB="${staticfile}" @@ -844,6 +877,12 @@ fi AC_SEARCH_LIBS([nl_handle_alloc], [nl], [AC_MSG_NOTICE([Unable to find nl library - may be needed by libpcap])]) +AC_CHECK_LIB(bpf, bpf_object__open_file,, + [AC_MSG_NOTICE([Unable to find libbpf library ])]) + +AC_CHECK_LIB(xdp, xsk_umem__delete,, + [AC_MSG_NOTICE([Unable to find libxdp library ])]) + ## ## If not automatically configured, ## check for newer and full-featured libpcap's @@ -928,7 +967,7 @@ cat >conftest.c </dev/null 2>&1 -if test -x conftest ; then +if test -x conftest -a "$cross_compiling" != "yes"; then full_libpcap_version=$(LD_LIBRARY_PATH="$LPCAP_LD_LIBRARY_PATH" ./conftest) libpcap_version=$(echo "$full_libpcap_version" | ${CUT} -d' ' -f3) pcap_version_ok=yes @@ -1184,6 +1223,35 @@ if test $have_pcap_snapshot = yes ; then [Does libpcap have pcap_snapshot?]) fi +have_pcap_open_offline_with_tstamp_precision=no +dnl Check to see if we've got pcap_open_offline_with_tstamp_precision() +AC_MSG_CHECKING(for pcap_open_offline_with_tstamp_precision support) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +#include "$LPCAPINC" +]],[[ + pcap_t *pcap; + char ebuf[PCAP_ERRBUF_SIZE]; + pcap = pcap_open_offline_with_tstamp_precision("fake.pcap", PCAP_TSTAMP_PRECISION_NANO, &ebuf[0]); +]])],[ + have_pcap_open_offline_with_tstamp_precision=yes + AC_MSG_RESULT(yes) +], [ + have_pcap_open_offline_with_tstamp_precision=no + AC_MSG_RESULT(no) +]) + +if test $have_pcap_open_offline_with_tstamp_precision = yes ; then + AC_DEFINE([HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION], [1], [Does libpcap have pcap_open_offline_with_tstamp_precision?]) + AC_DEFINE([PCAP_TSTAMP_US_TO_NS_MULTIPLIER], [1], [Multiplier for conversion from PCAP usec to nsec]) + AC_DEFINE([PCAP_TSTAMP_US_TO_US_DIVISOR], [1000], [Divisor for conversion from PCAP usec to usec]) +else + AC_DEFINE([PCAP_TSTAMP_US_TO_NS_MULTIPLIER], [1000], [Multiplier for conversion from PCAP usec to nsec]) + AC_DEFINE([PCAP_TSTAMP_US_TO_US_DIVISOR], [1], [Divisor for conversion from PCAP usec to usec]) +fi + # Tcpbridge requires libpcap and pcap_sendpacket() enable_tcpbridge=no @@ -1399,6 +1467,36 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ AC_MSG_RESULT(no) ]) +have_libxdp=no +dnl Check for LIBXDP AF_XDP socket support +AC_MSG_CHECKING(for LIBXDP XDP packet sending support) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +]], [[ + struct xsk_socket { + struct xsk_ring_cons *rx; + struct xsk_ring_prod *tx; + struct xsk_ctx *ctx; + struct xsk_socket_config config; + int fd; + }; + struct xsk_socket xsk; + struct xsk_ring_cons *rxr = NULL; + struct xsk_ring_prod *txr = NULL; + int queue_id = 0; + xsk_socket__create(&xsk, "lo", queue_id, NULL, rxr, txr, NULL); + socket(AF_XDP, SOCK_RAW, 0); +]])],[ + AC_DEFINE([HAVE_LIBXDP], [1], + [Do we have LIBXDP AF_XDP socket support?]) + AC_MSG_RESULT(yes) + have_libxdp=yes +],[ + AC_MSG_RESULT(no) +]) + have_tx_ring=no dnl Check for older Linux TX_RING support AC_MSG_CHECKING(for TX_RING socket sending support) @@ -1420,6 +1518,9 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ AC_MSG_RESULT(no) ]) +AC_CHECK_HEADERS([bpf/libbpf.h]) +AC_CHECK_HEADERS([bpf/bpf.h]) +AC_CHECK_HEADERS([xdp/libxdp.h]) AC_CHECK_HEADERS([net/bpf.h], [have_bpf=yes], [have_bpf=no]) if test $have_bpf = yes ; then @@ -1525,6 +1626,15 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "$LPCAPINC"]], [[ int foo; ],[AC_MSG_RESULT(no) ]) +AC_MSG_CHECKING(for DLT_LINUX_SLL2 in libpcap) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "$LPCAPINC"]], [[ int foo; + foo = DLT_LINUX_SLL2 + ]])],[ AC_DEFINE([HAVE_DLT_LINUX_SLL2], [1], + [Does pcap.h include a header with DLT_LINUX_SLL2?]) + AC_MSG_RESULT(yes) + ],[AC_MSG_RESULT(no) + ]) + AC_MSG_CHECKING(for DLT_C_HDLC in libpcap) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "$LPCAPINC"]], [[ int foo; foo = DLT_C_HDLC ]])],[ AC_DEFINE([HAVE_DLT_C_HDLC], [1], @@ -1709,7 +1819,7 @@ case "$host_os" in EOF ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \ conftest.c $LIBS >/dev/null 2>&1 - if test ! -x conftest ; then + if test ! -x conftest -o "$cross_compiling" = "yes" ; then dnl failed to compile for some reason unaligned_cv_fail=yes else @@ -1939,6 +2049,7 @@ pcap_sendpacket: ${have_pcap_sendpacket} ** pcap_netmap ${have_pcap_netmap} Linux/BSD netmap: ${have_netmap} Tuntap device support: ${have_tuntap} +LIBXDP for AF_XDP socket: ${have_libxdp} * In order of preference; see configure --help to override ** Required for tcpbridge diff --git a/docs/CHANGELOG b/docs/CHANGELOG index ca8129e82..ae814c949 100644 --- a/docs/CHANGELOG +++ b/docs/CHANGELOG @@ -1,7 +1,38 @@ +06/08/2024 Version 4.5.0-beta2 + - add -w (--suppress-warnings) option to suppress warning messages (#878) + - AF_XDP compile issue due to merge issue (#876) + - memory leak in tcpprep when using include/exclude (#869) + - memory leak in tcpprep when using RegEx (#867) + - fix nanosecond timestamp regression bug (#863) + - autotools - AC_HELP_STRING is obsolete in 2.70 (#856) + - configure.ac: do not run conftest in case of cross compilation (#849) + - Haiku support (#847) + - --fixhdrlen option added to control action on packet length changes (#846) + - incorrect checksum for certain IPv4 packets - fixed by #846 (#844) + - add check for IPv6 extension header length (#827 #842) + - GitHub template for pull requests (#839) + - improved 802.3 (Ethernet I) handling and warning messages (#835) + - handle IPv6 fragment extension header (#832 #837) + - Linux tap interfaces fail intermittently (#828) + - Infinite loop in tcprewrite at get.c (#827 #842) + - SLL incorrect size and protocol when converted to Ethernet (#826) + - CVE-2023-43279 add check for empty CIDR (#824 #843) + - AF_XDP socket extension (#822 #823) + - configure.ac: unify search dirs for pcap and add lib32 (#819) + - tcpreplay-edit recomputes IPv4 checksums unnecessarily (#815 #846) + - CVE-2023-4256 double free in tcprewrite DLT_JUNIPER_ETHER (#813 #851) + - dlt_jnpr_ether_cleanup: check config before cleanup (#812 #851) + - SEGV on invalid Juniper Ethernet header length (#811) + - nanosecond timestamps support (#796) + - Linux cooked packet fatal error (#792) + - low PPS values run at full speed after several days (#779) + - create DLT_LINUX_SLL2 plugin (#727) + 06/04/2023 Version 4.4.4 - overflow check fix for parse_mpls (#795) - tcpreplay-edit: prevent L2 flooding of ipv6 unicast packets (#793) - - CVE-2023-27786 bugs caused by strtok_r (#782 #784 #785 #786 #787 #788) + - CVE-2023-27784 CVE-2023-27785 CVE-2023-27786 CVE-2023-27787 CVE-2023-27788 CVE-2023-27789 + bugs caused by strtok_r (#782 #784 #785 #786 #787 #788) - CVE-2023-27783 reachable assert in tcpedit_dlt_cleanup (#780) - add CI and C/C++ Linter and CodeQL (#773) - reachable assert in fast_edit_packet (#772) @@ -33,15 +64,16 @@ - build failures Debian/kfreebsd (#706) - bus error when building on armhf (#705) - typo fixes (#704) - - heap buffer overflow in tcpreplay (#703) - - double free in Juniper DLT (#702) + - CVE-2022-27418 heap buffer overflow in tcpreplay (#703) + - CVE-2022-27416 double free in Juniper DLT (#702) 01/31/2022 Version 4.4.0 - remove obsolete FORCE_ALIGN support to fix macOS 11 compile (#695) - add a security policy document (#689) + - CVE-2021-45386 CVE-2021-45387 two reachable assertions in add_tree_ipv4() and add_tree_ipv6() (#687 #678) - ability to specify directory of pcap files (#682) - incorrect PPS rate for long-running sessions (#679) - - option --skipbroadcast not working (#677) + - option --skipbroadcast not working (#677 #678) - revert #630 to fix --multiplier issues (#674) - gcc 9.3 compiler warnings (#670) - installed netmap not automatically detected (#669) @@ -80,7 +112,7 @@ - CVE-2018-20553 Correct L2 header length calculations so that IP header offset is correct (#584) - Correct L2 header length to correct IP header offset (#583) - Fix warnings from gcc version 10 (#580) - - Heap Buffer Overflow in randomize_iparp (#579) + - CVE-2020-23273 Heap Buffer Overflow in randomize_iparp (#579) - Use after free in get_ipv6_next (#578) - CVE-2020-12740 Heap Buffer Overflow in git_ipv6_next (#576) - Call pcap_freecode() on pcap_compile() (#572) @@ -88,7 +120,7 @@ - Fix divide by zero in fuzzing (#570) - Unique IP repeats at very high iteration counts (#566) - Fails to compile on FreeBSD amd64 13.0 (#558) - - Heap Buffer Overflow in do_checksum (#556) (#577) + - CVE-2020-18976 Heap Buffer Overflow in do_checksum (#556) (#577) - Attempt to correct corrupt pcap files, if possible (#557) - Fix GCC v10 warnings (#555) - Remove some duplicated SOURCES entries (#551) diff --git a/docs/CREDIT b/docs/CREDIT index 467e076cb..f35d208f1 100644 --- a/docs/CREDIT +++ b/docs/CREDIT @@ -113,3 +113,28 @@ Florian Weimer David Guti - prevent L2 flooding of ipv6 unicast packets for tcpreplay-edit + +Bastian Triller + - Linux SLL2 + +GithHub @plangarbalint + - eBPF (AF_XDF) + - nanosecond timers + +Chuck Cottrill + - handle IPv6 fragment extensions + - --fixhdrlen option + - bug fixes + +Martin 'JaMa' Jansa + - configure.ac: unify search dirs for pcap and add lib32 + +Marsman + - dlt_jnpr_ether_cleanup: check config before cleanup + +Chen Qi + - configure.ac: do not run conftest in case of cross compilation + +Denis Ovsienko + - Haiku support + diff --git a/docs/INSTALL b/docs/INSTALL index ae077a6a3..bb47ba927 100644 --- a/docs/INSTALL +++ b/docs/INSTALL @@ -128,6 +128,35 @@ directory, for example: make sudo make install +2) AF_XDF + ------ + +This feature will detect AF_XDP capable network drivers on Linux. If detected, +the `--xdp` option becomes available, allowing eBPF enabled adapters to be +written to directly. + +This feature requires `libxdp-dev` and `libbpf-dev` packages to be installed. +For example: + + $ sudo apt install -y libxdp-dev libbpf-dev + $ ./configure | tail + Linux/BSD netmap: no + Tuntap device support: yes + LIBXDP for AF_XDP socket: yes + $ make + $ sudo make install + $ tcpreplay -i eth0 --xdp test/test.pcap + +If you want to compile a version that only uses AF_XDP, use the `--enable-force-libxdp` +configure option, e.g. + + $ ./configure --enable-force-libxdp | tail + Linux/BSD netmap: no + Tuntap device support: yes + LIBXDP for AF_XDP socket: yes + $ make + $ sudo make install + $ tcpreplay -i eth0 test/test.pcap Compilers and Options ===================== diff --git a/lib/sll.h b/lib/sll.h index 4f278792f..78e97fefd 100644 --- a/lib/sll.h +++ b/lib/sll.h @@ -1,10 +1,10 @@ /*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed - * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without @@ -42,30 +42,30 @@ * For captures on Linux cooked sockets, we construct a fake header * that includes: * - * a 2-byte "packet type" which is one of: + * a 2-byte "packet type" which is one of: * - * LINUX_SLL_HOST packet was sent to us - * LINUX_SLL_BROADCAST packet was broadcast - * LINUX_SLL_MULTICAST packet was multicast - * LINUX_SLL_OTHERHOST packet was sent to somebody else - * LINUX_SLL_OUTGOING packet was sent *by* us; + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; * - * a 2-byte Ethernet protocol field; + * a 2-byte Ethernet protocol field; * - * a 2-byte link-layer type; + * a 2-byte link-layer type; * - * a 2-byte link-layer address length; + * a 2-byte link-layer address length; * - * an 8-byte source link-layer address, whose actual length is - * specified by the previous value. + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. * * All fields except for the link-layer address are in network byte order. * * DO NOT change the layout of this structure, or change any of the * LINUX_SLL_ values below. If you must change the link-layer header * for a "cooked" Linux capture, introduce a new DLT_ type (ask - * "tcpdump-workers@tcpdump.org" for one, so that you don't give it a - * value that collides with a value already being used), and use the + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the * new header in captures of that type, so that programs that can * handle DLT_LINUX_SLL captures will continue to handle them correctly * without any change, and so that capture files with different headers @@ -77,54 +77,77 @@ #ifndef _SLL_H_ #define _SLL_H_ +//#include +#include + /* * A DLT_LINUX_SLL fake link-layer header. */ -#define SLL_HDR_LEN 16 /* total header length */ -#define SLL_ADDRLEN 8 /* length of address field */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ struct sll_header { - u_int16_t sll_pkttype; /* packet type */ - u_int16_t sll_hatype; /* link-layer address type */ - u_int16_t sll_halen; /* link-layer address length */ + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ - u_int16_t sll_protocol; /* protocol */ + u_int16_t sll_protocol; /* protocol */ +}; + +/* + * A DLT_LINUX_SLL2 fake link-layer header. + */ +#define SLL2_HDR_LEN 20 /* total header length */ + +struct sll2_header { + u_int16_t sll2_protocol; /* protocol */ + u_int16_t sll2_reserved_mbz; /* reserved - must be zero */ + u_int32_t sll2_if_index; /* 1-based interface index */ + u_int16_t sll2_hatype; /* link-layer address type */ + u_int8_t sll2_pkttype; /* packet type */ + u_int8_t sll2_halen; /* link-layer address length */ + u_int8_t sll2_addr[SLL_ADDRLEN]; /* link-layer address */ }; /* - * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the - * PACKET_ values on Linux, but are defined here so that they're - * available even on systems other than Linux, and so that they - * don't change even if the PACKET_ values change. + * The LINUX_SLL_ values for "sll_pkttype" and LINUX_SLL2_ values for + * "sll2_pkttype"; these correspond to the PACKET_ values on Linux, + * which are defined by a header under include/uapi in the current + * kernel source, and are thus not going to change on Linux. We + * define them here so that they're available even on systems other + * than Linux. */ -#define LINUX_SLL_HOST 0 -#define LINUX_SLL_BROADCAST 1 -#define LINUX_SLL_MULTICAST 2 -#define LINUX_SLL_OTHERHOST 3 -#define LINUX_SLL_OUTGOING 4 +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 /* - * The LINUX_SLL_ values for "sll_protocol"; these correspond to the - * ETH_P_ values on Linux, but are defined here so that they're - * available even on systems other than Linux. We assume, for now, - * that the ETH_P_ values won't change in Linux; if they do, then: + * The LINUX_SLL_ values for "sll_protocol" and LINUX_SLL2_ values for + * "sll2_protocol"; these correspond to the ETH_P_ values on Linux, but + * are defined here so that they're available even on systems other than + * Linux. We assume, for now, that the ETH_P_ values won't change in + * Linux; if they do, then: * - * if we don't translate them in "pcap-linux.c", capture files - * won't necessarily be readable if captured on a system that - * defines ETH_P_ values that don't match these values; + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; * - * if we do translate them in "pcap-linux.c", that makes life - * unpleasant for the BPF code generator, as the values you test - * for in the kernel aren't the values that you test for when - * reading a capture file, so the fixup code run on BPF programs - * handed to the kernel ends up having to do more work. + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. * * Add other values here as necessary, for handling packet types that * might show up on non-Ethernet, non-802.x networks. (Not all the ones * in the Linux "if_ether.h" will, I suspect, actually show up in * captures.) */ -#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ -#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ +#define LINUX_SLL_P_CAN 0x000C /* CAN frames, with SocketCAN pseudo-headers */ +#define LINUX_SLL_P_CANFD 0x000D /* CAN FD frames, with SocketCAN pseudo-headers */ #endif diff --git a/lib/strlcpy.h b/lib/strlcpy.h index 45a900c90..a3cc65d46 100644 --- a/lib/strlcpy.h +++ b/lib/strlcpy.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/libopts/m4/libopts.m4 b/libopts/m4/libopts.m4 index 23738cab4..3c271b1e8 100644 --- a/libopts/m4/libopts.m4 +++ b/libopts/m4/libopts.m4 @@ -478,7 +478,7 @@ AC_DEFUN([LIBOPTS_CHECK_COMMON],[ m4_pushdef([AO_Libopts_Dir], [ifelse($1, , [libopts], [$1])]) AC_ARG_ENABLE([local-libopts], - AC_HELP_STRING([--enable-local-libopts], + AS_HELP_STRING([--enable-local-libopts], [Use the supplied libopts tearoff code]),[ if test x$enableval = xyes ; then AC_MSG_NOTICE([Using supplied libopts tearoff]) @@ -488,14 +488,14 @@ AC_DEFUN([LIBOPTS_CHECK_COMMON],[ fi]) AC_ARG_ENABLE([libopts-install], - AC_HELP_STRING([--enable-libopts-install], + AS_HELP_STRING([--enable-libopts-install], [Install libopts with client installation])) AM_CONDITIONAL([INSTALL_LIBOPTS],[test "X${enable_libopts_install}" = Xyes]) [if test -z "${NEED_LIBOPTS_DIR}" ; then] AC_MSG_CHECKING([whether autoopts-config can be found]) AC_ARG_WITH([autoopts-config], - AC_HELP_STRING([--with-autoopts-config], + AS_HELP_STRING([--with-autoopts-config], [specify the config-info script]), [lo_cv_with_autoopts_config=${with_autoopts_config}], AC_CACHE_CHECK([whether autoopts-config is specified], diff --git a/src/bridge.c b/src/bridge.c index 970b753df..d136832bb 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -210,8 +210,8 @@ do_bridge(tcpbridge_opt_t *options, tcpedit_t *tcpedit) do_bridge_bidirectional(options, tcpedit); } - if (gettimeofday(&stats.end_time, NULL) < 0) - errx(-1, "gettimeofday() failed: %s", strerror(errno)); + if (get_current_time(&stats.end_time) < 0) + errx(-1, "get_current_time() failed: %s", strerror(errno)); packet_stats(&stats); } diff --git a/src/bridge.h b/src/bridge.h index bb7783682..d56510141 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common.h b/src/common.h index dd57f08df..fd207c2a4 100644 --- a/src/common.h +++ b/src/common.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/cache.c b/src/common/cache.c index d268463d9..353879e70 100644 --- a/src/common/cache.c +++ b/src/common/cache.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/cache.h b/src/common/cache.h index f064ebdcf..f38e70b5c 100644 --- a/src/common/cache.h +++ b/src/common/cache.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/cidr.c b/src/common/cidr.c index 687fd04b7..d4fc302b3 100644 --- a/src/common/cidr.c +++ b/src/common/cidr.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -249,6 +249,10 @@ parse_cidr(tcpr_cidr_t **cidrdata, char *cidrin, char *delim) char *network; char *token = NULL; + if (cidrin == NULL) { + errx(-1, "%s", "Unable to parse empty CIDR"); + } + mask_cidr6(&cidrin, delim); /* first iteration of input using strtok */ diff --git a/src/common/cidr.h b/src/common/cidr.h index e2fb475c4..52d706544 100644 --- a/src/common/cidr.h +++ b/src/common/cidr.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/dlt_names.c b/src/common/dlt_names.c index de694f207..d0b60ecfe 100644 --- a/src/common/dlt_names.c +++ b/src/common/dlt_names.c @@ -506,6 +506,28 @@ char *dlt2name[] = { "Unknown", "Unknown", "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "DLT_LINUX_SLL2", NULL }; diff --git a/src/common/dlt_names.h b/src/common/dlt_names.h index dfd437949..3f3534a3c 100644 --- a/src/common/dlt_names.h +++ b/src/common/dlt_names.h @@ -186,6 +186,10 @@ extern const char *dlt2name[]; #define DLT_LINUX_SLL 113 #endif +#ifndef DLT_LINUX_SLL2 +#define DLT_LINUX_SLL2 276 +#endif + #ifndef DLT_LTALK #define DLT_LTALK 114 #endif diff --git a/src/common/err.c b/src/common/err.c index 6f16ff7e3..606e1ecb0 100644 --- a/src/common/err.c +++ b/src/common/err.c @@ -7,7 +7,7 @@ * * Copyright (c) 2001-2010 Aaron Turner. * - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * Copyright (c) 2000 Dug Song * @@ -50,6 +50,8 @@ #include #include +int print_warnings = 1; + /** * writes a notice message to stderr. Always forces a newline */ diff --git a/src/common/err.h b/src/common/err.h index 57afb8358..62424f44f 100644 --- a/src/common/err.h +++ b/src/common/err.h @@ -7,7 +7,7 @@ * * Copyright (c) 2001-2010 Aaron Turner. * - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * Copyright (c) 2000 Dug Song * @@ -50,6 +50,8 @@ #include "defines.h" #include +extern int print_warnings; + #ifdef DEBUG extern int debug; #endif @@ -84,12 +86,14 @@ void notice(const char *fmt, ...); fprintf(stderr, "DEBUG%d in %s:%s() line %d: " y "\n", x, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \ } \ } while(0) - - -#define warn(x) fprintf(stderr, "Warning in %s:%s() line %d:\n%s\n", __FILE__, __FUNCTION__, __LINE__, x) +#define warn(x) \ + if (print_warnings) \ + fprintf(stderr, "Warning in %s:%s() line %d:\n%s\n", __FILE__, __FUNCTION__, __LINE__, x) -#define warnx(x, ...) fprintf(stderr, "Warning in %s:%s() line %d:\n" x "\n", __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) +#define warnx(x, ...) \ + if (print_warnings) \ + fprintf(stderr, "Warning in %s:%s() line %d:\n" x "\n", __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) #define err(x, y) do { \ fprintf(stderr, "\nFatal Error in %s:%s() line %d:\n%s\n", __FILE__, __FUNCTION__, __LINE__, y); \ diff --git a/src/common/fakepcap.c b/src/common/fakepcap.c index cf69b4500..88a9fe541 100644 --- a/src/common/fakepcap.c +++ b/src/common/fakepcap.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/fakepcap.h b/src/common/fakepcap.h index fd0efd905..0f35c9c9a 100644 --- a/src/common/fakepcap.h +++ b/src/common/fakepcap.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -29,6 +29,10 @@ #define DLT_LINUX_SLL 113 #endif +#ifndef HAVE_DLT_LINUX_SLL2 +#define DLT_LINUX_SLL2 276 +#endif + #ifndef HAVE_DLT_C_HDLC #define DLT_C_HDLC 104 #endif diff --git a/src/common/fakepcapnav.c b/src/common/fakepcapnav.c index 057c97109..2c103291e 100644 --- a/src/common/fakepcapnav.c +++ b/src/common/fakepcapnav.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -26,6 +26,7 @@ #include "defines.h" #include "config.h" #include "common.h" +#include "utils.h" #include #ifndef HAVE_PCAPNAV @@ -52,7 +53,7 @@ pcapnav_open_offline(const char *filename) err(-1, "malloc() error: unable to malloc pcapnav_t"); } - pcapnav->pcap = pcap_open_offline(filename, errbuf); + pcapnav->pcap = tcpr_pcap_open(filename, errbuf); if (pcapnav->pcap == NULL) { errx(-1, "Error opening pcap file %s: %s", filename, errbuf); } diff --git a/src/common/fakepcapnav.h b/src/common/fakepcapnav.h index a1f862502..e86445ba9 100644 --- a/src/common/fakepcapnav.h +++ b/src/common/fakepcapnav.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/flows.c b/src/common/flows.c index 28a4615a9..0fcb634ff 100644 --- a/src/common/flows.c +++ b/src/common/flows.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -157,8 +157,13 @@ static inline flow_entry_type_t hash_put_data(flow_hash_table_t *fht, const uint /* * Decode the packet, study it's flow status and report */ -flow_entry_type_t flow_decode(flow_hash_table_t *fht, const struct pcap_pkthdr *pkthdr, - const u_char *pktdata, const int datalink, const int expiry) +flow_entry_type_t +flow_decode(flow_hash_table_t *fht, + const struct pcap_pkthdr *pkthdr, + const u_char *pktdata, + const int datalink, + const int expiry, + COUNTER packetnum) { uint32_t pkt_len = pkthdr->caplen; const u_char *packet = pktdata; @@ -195,30 +200,52 @@ flow_entry_type_t flow_decode(flow_hash_table_t *fht, const struct pcap_pkthdr * &vlan_offset); if (res == -1) { - warnx("Unable to process unsupported DLT type: %s (0x%x)", - pcap_datalink_val_to_description(datalink), datalink); + warnx("flow_decode failed to determine %s header length for packet " COUNTER_SPEC "", + pcap_datalink_val_to_description(datalink), + packetnum); return FLOW_ENTRY_INVALID; } if (ether_type == ETHERTYPE_IP) { - if (pkt_len < l2len + sizeof(ipv4_hdr_t)) - return FLOW_ENTRY_INVALID; + size_t required_len = sizeof(ipv4_hdr_t) + l2len; + if (pkt_len < required_len) { + warnx("flow_decode: packet " COUNTER_SPEC " needs at least %zd bytes for IPv4 header but only %d available", + packetnum, + required_len, + pkt_len); + return FLOW_ENTRY_INVALID; + } ip_hdr = (ipv4_hdr_t *)(packet + l2len); - if (ip_hdr->ip_v != 4) + if (ip_hdr->ip_v != 4) { + warnx("flow_decode: packet " COUNTER_SPEC " IPv4 header version should be 4 but instead is %u", + packetnum, + ip_hdr->ip_v); return FLOW_ENTRY_NON_IP; + } ip_len = ip_hdr->ip_hl * 4; protocol = ip_hdr->ip_p; entry.src_ip.in = ip_hdr->ip_src; entry.dst_ip.in = ip_hdr->ip_dst; } else if (ether_type == ETHERTYPE_IP6) { - if (pkt_len < l2len + sizeof(ipv6_hdr_t)) - return FLOW_ENTRY_INVALID; + size_t required_len = sizeof(ipv6_hdr_t) + l2len; + if (pkt_len < required_len) { + warnx("flow_decode: packet " COUNTER_SPEC " needs at least %zd bytes for IPv6 header but only %d available", + packetnum, + required_len, + pkt_len); + return FLOW_ENTRY_INVALID; + } - if ((packet[0] >> 4) != 6) + uint8_t ip6_version = packet[0] >> 4; + if (ip6_version != 6) { + warnx("flow_decode: packet " COUNTER_SPEC " IPv6 header version should be 6 but instead is %u", + packetnum, + ip6_version); return FLOW_ENTRY_NON_IP; + } ip6_hdr = (ipv6_hdr_t *)(packet + l2len); ip_len = sizeof(*ip6_hdr); @@ -238,30 +265,50 @@ flow_entry_type_t flow_decode(flow_hash_table_t *fht, const struct pcap_pkthdr * entry.protocol = protocol; switch (protocol) { - case IPPROTO_UDP: - if (pkt_len < (l2len + ip_len + sizeof(udp_hdr_t))) + case IPPROTO_UDP: { + size_t required_len = sizeof(udp_hdr_t) + l2len + ip_len; + if (pkt_len < required_len) { + warnx("flow_decode: packet " COUNTER_SPEC " needs at least %zd bytes for UDP header but only %d available", + packetnum, + required_len, + pkt_len); return FLOW_ENTRY_INVALID; - udp_hdr = (udp_hdr_t*)(packet + ip_len + l2len); + } + udp_hdr = (udp_hdr_t *)(packet + ip_len + l2len); entry.src_port = udp_hdr->uh_sport; entry.dst_port = udp_hdr->uh_dport; break; - - case IPPROTO_TCP: - if (pkt_len < (l2len + ip_len + sizeof(tcp_hdr_t))) + } + case IPPROTO_TCP: { + size_t required_len = sizeof(tcp_hdr_t) + l2len + ip_len; + if (pkt_len < required_len) { + warnx("flow_decode: packet " COUNTER_SPEC " needs at least %zd bytes for TCP header but only %d available", + packetnum, + required_len, + pkt_len); return FLOW_ENTRY_INVALID; - tcp_hdr = (tcp_hdr_t*)(packet + ip_len + l2len); + } + tcp_hdr = (tcp_hdr_t *)(packet + ip_len + l2len); entry.src_port = tcp_hdr->th_sport; entry.dst_port = tcp_hdr->th_dport; break; - + } case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - if (pkt_len < (l2len + ip_len + sizeof(icmpv4_hdr_t))) + case IPPROTO_ICMPV6: { + size_t required_len = sizeof(icmpv4_hdr_t) + l2len + ip_len; + if (pkt_len < required_len) { + warnx("flow_decode: packet " COUNTER_SPEC " needs at least %zd bytes for %s header but only %d available", + packetnum, + required_len, + (protocol == IPPROTO_ICMP) ? "ICMP" : "ICMPv6", + pkt_len); return FLOW_ENTRY_INVALID; - icmp_hdr = (icmpv4_hdr_t*)(packet + ip_len + l2len); + } + icmp_hdr = (icmpv4_hdr_t *)(packet + ip_len + l2len); entry.src_port = icmp_hdr->icmp_type; entry.dst_port = icmp_hdr->icmp_code; break; + } default: entry.src_port = 0; entry.dst_port = 0; diff --git a/src/common/flows.h b/src/common/flows.h index 14a02f755..73e487c4c 100644 --- a/src/common/flows.h +++ b/src/common/flows.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -38,4 +38,5 @@ flow_entry_type_t flow_decode(flow_hash_table_t *fht, const struct pcap_pkthdr *pkthdr, const u_char *pktdata, const int datalink, - const int expiry); + const int expiry, + COUNTER packetnum); diff --git a/src/common/get.c b/src/common/get.c index eec352801..5538a86ff 100644 --- a/src/common/get.c +++ b/src/common/get.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -41,8 +41,8 @@ extern const char pcap_version[]; static void *get_ipv6_next(struct tcpr_ipv6_ext_hdr_base *exthdr, const u_char *end_ptr); /** - * Depending on what version of libpcap/WinPcap there are different ways to get - * the version of the libpcap/WinPcap library. This presents a unified way to + * Depending on what version of libpcap there are different ways to get + * the version of the libpcap library. This presents a unified way to * get that information. */ const char * @@ -461,19 +461,29 @@ get_l2len_protocol(const u_char *pktdata, *protocol = ETHERTYPE_IP6; break; case DLT_JUNIPER_ETHER: - if (datalen < 4) + if (datalen < 4) { + warnx("%s (0x%x): Need at least 4 bytes for DLT_JUNIPER_ETHER but only %u available", + pcap_datalink_val_to_description(datalink), + datalink, + datalen); return -1; + } if (memcmp(pktdata, JUNIPER_PCAP_MAGIC, 3) != 0) { - warnx("No Magic Number found during protocol lookup: %s (0x%x)", + warnx("%s (0x%x): No JUNIPER_PCAP_MAGIC Magic Number found during protocol lookup", pcap_datalink_val_to_description(datalink), datalink); return -1; } if ((pktdata[3] & JUNIPER_FLAG_EXT) == JUNIPER_FLAG_EXT) { - if (datalen < 6) + if (datalen < 6) { + warnx("%s (0x%x): Need at least 6 bytes for JUNIPER_FLAG_EXT but only %u available", + pcap_datalink_val_to_description(datalink), + datalink, + datalen); return -1; + } *l2offset = ntohs(*((uint16_t *)&pktdata[4])); *l2offset += 6; /* MGC + flags + ext_total_len */ @@ -484,8 +494,15 @@ get_l2len_protocol(const u_char *pktdata, if ((pktdata[3] & JUNIPER_FLAG_NO_L2) == JUNIPER_FLAG_NO_L2) { /* no L2 header present - *l2offset is actually IP offset */ uint32_t ip_hdr_offset = *l2offset; - if (datalen < ip_hdr_offset + 1) + uint32_t hdrSpaceNeeded = ip_hdr_offset + 1; + if (datalen < hdrSpaceNeeded) { + warnx("%s (0x%x): Need at least %u bytes for JUNIPER_FLAG_NO_L2 but only %u available", + pcap_datalink_val_to_description(datalink), + hdrSpaceNeeded, + datalink, + datalen); return -1; + } if ((pktdata[ip_hdr_offset] >> 4) == 4) *protocol = ETHERTYPE_IP; @@ -501,36 +518,46 @@ get_l2len_protocol(const u_char *pktdata, uint16_t ether_type; uint32_t l2_net_off = sizeof(*eth_hdr) + *l2offset; - if (datalen <= l2_net_off) + if (datalen <= l2_net_off + 4) { + warnx("%s (0x%x): Need at least %u bytes for DLT_EN10MB but only %u available", + pcap_datalink_val_to_description(datalink), + datalink, + l2_net_off + 4, + datalen); return -1; + } eth_hdr = (eth_hdr_t *)(pktdata + *l2offset); ether_type = ntohs(eth_hdr->ether_type); if (parse_metadata(pktdata, datalen, ðer_type, &l2_net_off, l2offset, vlan_offset)) return -1; - if (datalen <= l2_net_off) - return -1; - *l2len = l2_net_off; - if (ether_type > 1500) { + if (ether_type >= 1536) { /* Ethernet II frame - return in host order */ *protocol = ether_type; + } else if (ether_type > 1500) { + warnx("%s (0x%x): unsupported 802.3 length %u", + pcap_datalink_val_to_description(datalink), + datalink, + ether_type); + return -1; } else { /* 803.3 frame */ - if ((pktdata[l2_net_off] >> 4) == 4) - *protocol = ETHERTYPE_IP; - else if ((pktdata[l2_net_off] >> 4) == 6) - *protocol = ETHERTYPE_IP6; - else - /* unsupported 802.3 protocol */ - return -1; + /* we don't modify 802.3 protocols */ + return -1; } break; } case DLT_PPP_SERIAL: - if ((size_t)datalen < sizeof(struct tcpr_pppserial_hdr)) + if ((size_t)datalen < sizeof(struct tcpr_pppserial_hdr)) { + warnx("%s (0x%x): Need at least %zu bytes for DLT_PPP_SERIAL but only %u available", + pcap_datalink_val_to_description(datalink), + datalink, + sizeof(struct tcpr_pppserial_hdr), + datalen); return -1; + } struct tcpr_pppserial_hdr *ppp = (struct tcpr_pppserial_hdr *)pktdata; *l2len = sizeof(*ppp); @@ -541,21 +568,47 @@ get_l2len_protocol(const u_char *pktdata, break; case DLT_C_HDLC: - if (datalen < CISCO_HDLC_LEN) + if (datalen < CISCO_HDLC_LEN) { + warnx("%s (0x%x): Need at least %u bytes for DLT_C_HDLC but only %u available", + pcap_datalink_val_to_description(datalink), + datalink, + CISCO_HDLC_LEN, + datalen); return -1; + } hdlc_hdr_t *hdlc_hdr = (hdlc_hdr_t *)pktdata; *l2len = sizeof(*hdlc_hdr); *protocol = ntohs(hdlc_hdr->protocol); break; case DLT_LINUX_SLL: - if (datalen < SLL_HDR_LEN) + if (datalen < SLL_HDR_LEN) { + warnx("%s (0x%x): Need at least %u bytes for DLT_LINUX_SLL but only %u available", + pcap_datalink_val_to_description(datalink), + datalink, + SLL_HDR_LEN, + datalen); return -1; + } + *l2len = SLL_HDR_LEN; sll_hdr_t *sll_hdr = (sll_hdr_t *)pktdata; - *l2len = sizeof(*sll_hdr); *protocol = ntohs(sll_hdr->sll_protocol); break; + case DLT_LINUX_SLL2: + if (datalen < SLL2_HDR_LEN) { + warnx("%s (0x%x): Need at least %u bytes for DLT_LINUX_SLL2 but only %u available", + pcap_datalink_val_to_description(datalink), + datalink, + SLL2_HDR_LEN, + datalen); + return -1; + } + + *l2len = SLL2_HDR_LEN; + sll2_hdr_t *sll2_hdr = (sll2_hdr_t *)pktdata; + *protocol = ntohs(sll2_hdr->sll2_protocol); + break; default: errx(-1, "Unable to process unsupported DLT type: %s (0x%x)", @@ -788,9 +841,25 @@ get_layer4_v6(const ipv6_hdr_t *ip6_hdr, const u_char *end_ptr) break; /* - * Can't handle. Unparsable IPv6 fragment/encrypted data + * handle (unparsable) IPv6 fragment data */ case TCPR_IPV6_NH_FRAGMENT: + // next points to l4 data + dbgx(3, "Go deeper due to fragment extension header 0x%02X", proto); + exthdr = get_ipv6_next(next, end_ptr); + if ((exthdr == NULL) || ((u_char *)exthdr > end_ptr)) { + next = NULL; + done = true; + break; + } + proto = exthdr->ip_nh; + next = exthdr; + // done = true; + break; + + /* + * Can't handle. Unparsable IPv6 encrypted data + */ case TCPR_IPV6_NH_ESP: next = NULL; done = true; @@ -800,9 +869,11 @@ get_layer4_v6(const ipv6_hdr_t *ip6_hdr, const u_char *end_ptr) * no further processing, either TCP, UDP, ICMP, etc... */ default: - if (proto != ip6_hdr->ip_nh) { + if (proto != ip6_hdr->ip_nh && next) { dbgx(3, "Returning byte offset of this ext header: %u", IPV6_EXTLEN_TO_BYTES(next->ip_len)); next = (void *)((u_char *)next + IPV6_EXTLEN_TO_BYTES(next->ip_len)); + if ((u_char*)next > end_ptr) + return NULL; } else { dbgx(3, "%s", "Returning end of IPv6 Header"); } @@ -858,6 +929,10 @@ get_ipv6_next(struct tcpr_ipv6_ext_hdr_base *exthdr, const u_char *end_ptr) case TCPR_IPV6_NH_HBH: case TCPR_IPV6_NH_AH: extlen = IPV6_EXTLEN_TO_BYTES(exthdr->ip_len); + if (extlen == 0) { + dbg(3, "Malformed IPv6 extension header..."); + return NULL; + } dbgx(3, "Looks like we're an ext header (0x%hhx). Jumping %u bytes" " to the next", diff --git a/src/common/get.h b/src/common/get.h index 6e1988ff9..3961d9b43 100644 --- a/src/common/get.h +++ b/src/common/get.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/interface.c b/src/common/interface.c index 006f7133d..b94f6e3d7 100644 --- a/src/common/interface.c +++ b/src/common/interface.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/interface.h b/src/common/interface.h index 446b51a33..b28390489 100644 --- a/src/common/interface.h +++ b/src/common/interface.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/list.c b/src/common/list.c index ec41dd12b..5075fd5a7 100644 --- a/src/common/list.c +++ b/src/common/list.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/list.h b/src/common/list.h index 9eaa425fa..7eb3b5ae9 100644 --- a/src/common/list.h +++ b/src/common/list.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/mac.c b/src/common/mac.c index 45e45facd..88e675a09 100644 --- a/src/common/mac.c +++ b/src/common/mac.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/mac.h b/src/common/mac.h index 50116a8e9..275671cb8 100644 --- a/src/common/mac.h +++ b/src/common/mac.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/pcap_dlt.h b/src/common/pcap_dlt.h index 2d5827821..767854b6c 100644 --- a/src/common/pcap_dlt.h +++ b/src/common/pcap_dlt.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/sendpacket.c b/src/common/sendpacket.c index 9dc378f6d..7d966dd61 100644 --- a/src/common/sendpacket.c +++ b/src/common/sendpacket.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -63,6 +63,7 @@ #undef HAVE_PCAP_INJECT #undef HAVE_PCAP_SENDPACKET #undef HAVE_BPF +#undef HAVE_LIBXDP #endif #ifdef FORCE_INJECT_PF_PACKET @@ -71,6 +72,7 @@ #undef HAVE_PCAP_INJECT #undef HAVE_PCAP_SENDPACKET #undef HAVE_BPF +#undef HAVE_LIBXDP #endif #ifdef FORCE_INJECT_LIBDNET @@ -79,6 +81,7 @@ #undef HAVE_PCAP_INJECT #undef HAVE_PCAP_SENDPACKET #undef HAVE_BPF +#undef HAVE_LIBXDP #endif #ifdef FORCE_INJECT_BPF @@ -87,6 +90,7 @@ #undef HAVE_PCAP_INJECT #undef HAVE_PCAP_SENDPACKET #undef HAVE_PF_PACKET +#undef HAVE_LIBXDP #endif #ifdef FORCE_INJECT_PCAP_INJECT @@ -95,6 +99,7 @@ #undef HAVE_PCAP_SENDPACKET #undef HAVE_BPF #undef HAVE_PF_PACKET +#undef HAVE_LIBXDP #endif #ifdef FORCE_INJECT_PCAP_SENDPACKET @@ -103,6 +108,16 @@ #undef HAVE_PCAP_INJECT #undef HAVE_BPF #undef HAVE_PF_PACKET +#undef HAVE_LIBXDP +#endif + +#ifdef FORCE_INJECT_LIBXDP +#undef HAVE_TX_RING +#undef HAVE_LIBDNET +#undef HAVE_PF_PACKET +#undef HAVE_PCAP_INJECT +#undef HAVE_PCAP_SENDPACKET +#undef HAVE_BPF #endif #if (defined HAVE_WINPCAP && defined HAVE_PCAP_INJECT) @@ -110,16 +125,13 @@ #endif #if !defined HAVE_PCAP_INJECT && !defined HAVE_PCAP_SENDPACKET && !defined HAVE_LIBDNET && !defined HAVE_PF_PACKET && \ - !defined HAVE_BPF && !defined TX_RING -#error You need pcap_inject() or pcap_sendpacket() from libpcap, libdnet, Linux's PF_PACKET/TX_RING or *BSD's BPF + !defined HAVE_BPF && !defined TX_RING && !defined HAVE_LIBXDP +#error You need pcap_inject() or pcap_sendpacket() from libpcap, libdnet, Linux's PF_PACKET/TX_RING/AF_XDP with libxdp or *BSD's BPF #endif #ifdef HAVE_SYS_PARAM_H #include #endif -#ifdef HAVE_SYS_SYSCTL_H -#include -#endif #ifdef HAVE_NET_ROUTE_H #include #endif @@ -211,7 +223,15 @@ static struct tcpr_ether_addr *sendpacket_get_hwaddr_pcap(sendpacket_t *) _U_; #undef INJECT_METHOD #define INJECT_METHOD "pcap_sendpacket()" #endif - +#ifdef HAVE_LIBXDP +#include +static sendpacket_t *sendpacket_open_xsk(const char *, char *) _U_; +static struct tcpr_ether_addr *sendpacket_get_hwaddr_libxdp(sendpacket_t *); +#endif +#if defined HAVE_LIBXDP && !defined INJECT_METHOD +#undef INJECT_METHOD +#define INJECT_METHOD "xsk_ring_prod_submit()" +#endif static void sendpacket_seterr(sendpacket_t *sp, const char *fmt, ...); static sendpacket_t *sendpacket_open_khial(const char *, char *) _U_; static struct tcpr_ether_addr *sendpacket_get_hwaddr_khial(sendpacket_t *) _U_; @@ -237,7 +257,10 @@ sendpacket(sendpacket_t *sp, const u_char *data, size_t len, struct pcap_pkthdr static const size_t buffer_payload_size = sizeof(buffer) + sizeof(struct pcap_pkthdr); assert(sp); +#ifndef HAVE_LIBXDP + // In case of XDP packet processing we are storing data in sp->packet_processing->xdp_descs assert(data); +#endif if (len == 0) return -1; @@ -452,7 +475,18 @@ sendpacket(sendpacket_t *sp, const u_char *data, size_t len, struct pcap_pkthdr } #endif /* HAVE_NETMAP */ break; - + case SP_TYPE_LIBXDP: +#ifdef HAVE_LIBXDP + retcode = len; + xsk_ring_prod__submit(&(sp->xsk_info->tx), sp->pckt_count); // submit all packets at once + sp->xsk_info->ring_stats.tx_npkts += sp->pckt_count; + sp->xsk_info->outstanding_tx += sp->pckt_count; + while (sp->xsk_info->outstanding_tx != 0) { + complete_tx_only(sp); + } + sp->sent += sp->pckt_count; +#endif + break; default: errx(-1, "Unsupported sp->handle_type = %d", sp->handle_type); } /* end case */ @@ -465,8 +499,15 @@ sendpacket(sendpacket_t *sp, const u_char *data, size_t len, struct pcap_pkthdr sendpacket_seterr(sp, "Only able to write %d bytes out of %lu bytes total", retcode, len); sp->trunc_packets++; } else { +#ifndef HAVE_LIBXDP sp->bytes_sent += len; sp->sent++; +#else + if (sp->handle_type != SP_TYPE_LIBXDP) { + sp->bytes_sent += len; + sp->sent++; + } +#endif } return retcode; } @@ -483,10 +524,6 @@ sendpacket_open(const char *device, sendpacket_type_t sendpacket_type _U_, void *arg _U_) { -#ifdef HAVE_TUNTAP - char sys_dev_dir[128]; - bool device_exists; -#endif sendpacket_t *sp; struct stat sdata; @@ -495,11 +532,6 @@ sendpacket_open(const char *device, errbuf[0] = '\0'; -#ifdef HAVE_TUNTAP - snprintf(sys_dev_dir, sizeof(sys_dev_dir), "/sys/class/net/%s/", device); - device_exists = access(sys_dev_dir, R_OK) == 0; -#endif - /* khial is universal */ if (stat(device, &sdata) == 0) { if (((sdata.st_mode & S_IFMT) == S_IFCHR)) { @@ -522,7 +554,7 @@ sendpacket_open(const char *device, } } #ifdef HAVE_TUNTAP - } else if (strncmp(device, "tap", 3) == 0 && !device_exists) { + } else if (strncmp(device, "tap", 3) == 0) { sp = sendpacket_open_tuntap(device, errbuf); #endif } else { @@ -531,14 +563,21 @@ sendpacket_open(const char *device, sp = (sendpacket_t *)sendpacket_open_netmap(device, errbuf, arg); else #endif +#ifdef HAVE_LIBXDP + if (sendpacket_type == SP_TYPE_LIBXDP) + sp = sendpacket_open_xsk(device, errbuf); + else +#endif #if defined HAVE_PF_PACKET sp = sendpacket_open_pf(device, errbuf); #elif defined HAVE_BPF - sp = sendpacket_open_bpf(device, errbuf); + sp = sendpacket_open_bpf(device, errbuf); #elif defined HAVE_LIBDNET - sp = sendpacket_open_libdnet(device, errbuf); + sp = sendpacket_open_libdnet(device, errbuf); #elif (defined HAVE_PCAP_INJECT || defined HAVE_PCAP_SENDPACKET) - sp = sendpacket_open_pcap(device, errbuf); + sp = sendpacket_open_pcap(device, errbuf); +#elif defined HAVE_LIBXDP + sp = sendpacket_open_xsk(device, errbuf); #else #error "No defined packet injection method for sendpacket_open()" #endif @@ -647,6 +686,13 @@ sendpacket_close(sendpacket_t *sp) case SP_TYPE_TUNTAP: #ifdef HAVE_TUNTAP close(sp->handle.fd); +#endif + break; + case SP_TYPE_LIBXDP: +#ifdef HAVE_LIBXDP + close(sp->handle.fd); + safe_free(sp->xsk_info); + safe_free(sp->umem_info); #endif break; case SP_TYPE_NONE: @@ -674,6 +720,8 @@ sendpacket_get_hwaddr(sendpacket_t *sp) } else { #if defined HAVE_PF_PACKET addr = sendpacket_get_hwaddr_pf(sp); +#elif defined HAVE_LIBXDP + addr = sendpacket_get_hwaddr_libxdp(sp); #elif defined HAVE_BPF addr = sendpacket_get_hwaddr_bpf(sp); #elif defined HAVE_LIBDNET @@ -838,9 +886,12 @@ sendpacket_open_tuntap(const char *device, char *errbuf) strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1); if (ioctl(tapfd, TUNSETIFF, (void *)&ifr) < 0) { - snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to create tuntap interface: %s", device); - close(tapfd); - return NULL; + // ignore EBUSY - it just means that the tunnel has already been opened + if (errno != EBUSY) { + snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to create tuntap interface: %s errno=%d", device, errno); + close(tapfd); + return NULL; + } } #elif defined(HAVE_FREEBSD) if (*device == '/') { @@ -1066,7 +1117,7 @@ sendpacket_open_bpf(const char *device, char *errbuf) { sendpacket_t *sp; char bpf_dev[16]; - int dev, mysocket, link_offset, link_type; + int dev, mysocket; struct ifreq ifr; struct bpf_version bv; u_int v; @@ -1134,43 +1185,10 @@ sendpacket_open_bpf(const char *device, char *errbuf) } #endif - /* assign link type and offset */ - switch (v) { - case DLT_SLIP: - link_offset = 0x10; - break; - case DLT_RAW: - link_offset = 0x0; - break; - case DLT_PPP: - link_offset = 0x04; - break; - case DLT_EN10MB: - default: /* default to Ethernet */ - link_offset = 0xe; - break; - } -#if _BSDI_VERSION - 0 > 199510 - switch (v) { - case DLT_SLIP: - v = DLT_SLIP_BSDOS; - link_offset = 0x10; - break; - case DLT_PPP: - v = DLT_PPP_BSDOS; - link_offset = 0x04; - break; - } -#endif - - link_type = v; - /* allocate our sp handle, and return it */ sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t)); strlcpy(sp->device, device, sizeof(sp->device)); sp->handle.fd = mysocket; - // sp->link_type = link_type; - // sp->link_offset = link_offset; sp->handle_type = SP_TYPE_BPF; return sp; @@ -1236,30 +1254,36 @@ sendpacket_get_dlt(sendpacket_t *sp) { int dlt = DLT_EN10MB; - if (sp->handle_type == SP_TYPE_KHIAL || sp->handle_type == SP_TYPE_NETMAP || sp->handle_type == SP_TYPE_TUNTAP) { - /* always EN10MB */ - } else { -#if defined HAVE_BPF - int rcode; + switch (sp->handle_type) { + case SP_TYPE_KHIAL: + case SP_TYPE_NETMAP: + case SP_TYPE_TUNTAP: + case SP_TYPE_LIBXDP: + /* always EN10MB */ + return dlt; + default: + ; + } - if ((rcode = ioctl(sp->handle.fd, BIOCGDLT, &dlt)) < 0) { - warnx("Unable to get DLT value for BPF device (%s): %s", sp->device, strerror(errno)); - return (-1); - } +#if defined HAVE_BPF + if ((ioctl(sp->handle.fd, BIOCGDLT, &dlt)) < 0) { + warnx("Unable to get DLT value for BPF device (%s): %s", sp->device, strerror(errno)); + return (-1); + } #elif defined HAVE_PF_PACKET || defined HAVE_LIBDNET - /* use libpcap to get dlt */ - pcap_t *pcap; - char errbuf[PCAP_ERRBUF_SIZE]; - if ((pcap = pcap_open_live(sp->device, 65535, 0, 0, errbuf)) == NULL) { - warnx("Unable to get DLT value for %s: %s", sp->device, errbuf); - return (-1); - } - dlt = pcap_datalink(pcap); - pcap_close(pcap); + /* use libpcap to get dlt */ + pcap_t *pcap; + char errbuf[PCAP_ERRBUF_SIZE]; + if ((pcap = pcap_open_live(sp->device, 65535, 0, 0, errbuf)) == NULL) { + warnx("Unable to get DLT value for %s: %s", sp->device, errbuf); + return (-1); + } + dlt = pcap_datalink(pcap); + pcap_close(pcap); #elif defined HAVE_PCAP_SENDPACKET || defined HAVE_PCAP_INJECT - dlt = pcap_datalink(sp->handle.pcap); + dlt = pcap_datalink(sp->handle.pcap); #endif - } + return dlt; } @@ -1327,3 +1351,156 @@ sendpacket_abort(sendpacket_t *sp) sp->abort = true; } +#ifdef HAVE_LIBXDP +static struct xsk_socket_info * +xsk_configure_socket(struct xsk_umem_info *umem, struct xsk_socket_config *cfg, int queue_id, const char *device) +{ + struct xsk_socket_info *xsk; + struct xsk_ring_cons *rxr = NULL; + int ret; + + xsk = (struct xsk_socket_info *)safe_malloc(sizeof(struct xsk_socket_info)); + xsk->umem = umem; + ret = xsk_socket__create(&xsk->xsk, device, queue_id, umem->umem, rxr, &xsk->tx, cfg); + if (ret) { + return NULL; + } + + memset(&xsk->app_stats, 0, sizeof(xsk->app_stats)); + + return xsk; +} + +static sendpacket_t * +sendpacket_open_xsk(const char *device, char *errbuf) +{ + sendpacket_t *sp; + + assert(device); + assert(errbuf); + + int nb_of_frames = 4096; + int frame_size = 4096; + int nb_of_completion_queue_desc = 4096; + int nb_of_fill_queue_desc = 4096; + struct xsk_umem_info *umem_info = + create_umem_area(nb_of_frames, frame_size, nb_of_completion_queue_desc, nb_of_fill_queue_desc); + if (umem_info == NULL) { + return NULL; + } + + int nb_of_tx_queue_desc = 4096; + int nb_of_rx_queue_desc = 4096; + u_int32_t queue_id = 0; + struct xsk_socket_info *xsk_info = + create_xsk_socket(umem_info, nb_of_tx_queue_desc, nb_of_rx_queue_desc, device, queue_id, errbuf); + if (xsk_info == NULL) { + return NULL; + } + + sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t)); + strlcpy(sp->device, device, sizeof(sp->device)); + sp->handle.fd = xsk_info->xsk->fd; + sp->handle_type = SP_TYPE_LIBXDP; + sp->xsk_info = xsk_info; + sp->umem_info = umem_info; + sp->frame_size = frame_size; + sp->tx_size = nb_of_tx_queue_desc; + return sp; +} + +struct xsk_umem_info * +create_umem_area(int nb_of_frames, int frame_size, int nb_of_completion_queue_descs, int nb_of_fill_queue_descs) +{ + int umem_size = nb_of_frames * frame_size; + struct xsk_umem_info *umem; + void *umem_area = NULL; + struct xsk_umem_config cfg = {/* We recommend that you set the fill ring size >= HW RX ring size + + * AF_XDP RX ring size. Make sure you fill up the fill ring + * with buffers at regular intervals, and you will with this setting + * avoid allocation failures in the driver. These are usually quite + * expensive since drivers have not been written to assume that + * allocation failures are common. For regular sockets, kernel + * allocated memory is used that only runs out in OOM situations + * that should be rare. + */ + .fill_size = nb_of_fill_queue_descs * 2, + .comp_size = nb_of_completion_queue_descs, + .frame_size = frame_size, + .frame_headroom = 0, + .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG}; + umem = (struct xsk_umem_info *)safe_malloc(sizeof(struct xsk_umem_info)); + if (posix_memalign(&umem_area, + getpagesize(), /* PAGE_SIZE aligned */ + umem_size)) { + fprintf(stderr, "ERROR: Can't allocate buffer memory \"%s\"\n", strerror(errno)); + exit(EXIT_FAILURE); + } + int ret = xsk_umem__create(&umem->umem, umem_area, umem_size, &umem->fq, &umem->cq, &cfg); + umem->buffer = umem_area; + if (ret != 0) { + return NULL; + } + return umem; +} + +struct xsk_socket_info * +create_xsk_socket(struct xsk_umem_info *umem_info, + int nb_of_tx_queue_desc, + int nb_of_rx_queue_desc, + const char *device, + u_int32_t queue_id, + char *errbuf) +{ + struct xsk_socket_info *xsk_info = (struct xsk_socket_info *)safe_malloc(sizeof(struct xsk_socket_info)); + struct xsk_socket_config *socket_config = (struct xsk_socket_config *)safe_malloc(sizeof(struct xsk_socket_config)); + + socket_config->rx_size = nb_of_rx_queue_desc; + socket_config->tx_size = nb_of_tx_queue_desc; + socket_config->libbpf_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD; + socket_config->bind_flags = 0; // XDP_FLAGS_SKB_MODE (1U << 1) or XDP_FLAGS_DRV_MODE (1U << 2) + xsk_info = xsk_configure_socket(umem_info, socket_config, queue_id, device); + + if (xsk_info == NULL) { + snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "AF_XDP socket configuration is not successful: %s", strerror(errno)); + return NULL; + } + return xsk_info; +} + +/* + * gets the hardware address via Linux's PF packet interface + */ +static _U_ struct tcpr_ether_addr * +sendpacket_get_hwaddr_libxdp(sendpacket_t *sp) +{ + struct ifreq ifr; + int fd; + + assert(sp); + + if (!sp->open) { + sendpacket_seterr(sp, "Unable to get hardware address on un-opened sendpacket handle"); + return NULL; + } + + /* create dummy socket for ioctl */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + sendpacket_seterr(sp, "Unable to open dummy socket for get_hwaddr: %s", strerror(errno)); + return NULL; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, sp->device, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFHWADDR, (int8_t *)&ifr) < 0) { + close(fd); + sendpacket_seterr(sp, "Error getting hardware address: %s", strerror(errno)); + return NULL; + } + + memcpy(&sp->ether, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); + close(fd); + return (&sp->ether); +} +#endif /* HAVE_LIBXDP */ diff --git a/src/common/sendpacket.h b/src/common/sendpacket.h index e1dd6a424..a39072ee1 100644 --- a/src/common/sendpacket.h +++ b/src/common/sendpacket.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -26,7 +26,7 @@ #ifdef __NetBSD__ #include -#else +#elif ! defined(__HAIKU__) #include #endif @@ -67,7 +67,8 @@ typedef enum sendpacket_type_e { SP_TYPE_TX_RING, SP_TYPE_KHIAL, SP_TYPE_NETMAP, - SP_TYPE_TUNTAP + SP_TYPE_TUNTAP, + SP_TYPE_LIBXDP } sendpacket_type_t; /* these are the file_operations ioctls */ @@ -91,6 +92,71 @@ union sendpacket_handle { #define SENDPACKET_ERRBUF_SIZE 1024 #define MAX_IFNAMELEN 64 +#ifdef HAVE_LIBXDP +#include +#include +#include +#include + +struct xsk_ring_stats { + unsigned long rx_npkts; + unsigned long tx_npkts; + unsigned long rx_dropped_npkts; + unsigned long rx_invalid_npkts; + unsigned long tx_invalid_npkts; + unsigned long rx_full_npkts; + unsigned long rx_fill_empty_npkts; + unsigned long tx_empty_npkts; + unsigned long prev_rx_npkts; + unsigned long prev_tx_npkts; + unsigned long prev_rx_dropped_npkts; + unsigned long prev_rx_invalid_npkts; + unsigned long prev_tx_invalid_npkts; + unsigned long prev_rx_full_npkts; + unsigned long prev_rx_fill_empty_npkts; + unsigned long prev_tx_empty_npkts; +}; +struct xsk_driver_stats { + unsigned long intrs; + unsigned long prev_intrs; +}; +struct xsk_app_stats { + unsigned long rx_empty_polls; + unsigned long fill_fail_polls; + unsigned long copy_tx_sendtos; + unsigned long tx_wakeup_sendtos; + unsigned long opt_polls; + unsigned long prev_rx_empty_polls; + unsigned long prev_fill_fail_polls; + unsigned long prev_copy_tx_sendtos; + unsigned long prev_tx_wakeup_sendtos; + unsigned long prev_opt_polls; +}; +struct xsk_umem_info { + struct xsk_ring_prod fq; + struct xsk_ring_cons cq; + struct xsk_umem *umem; + void *buffer; +}; +struct xsk_socket { + struct xsk_ring_cons *rx; + struct xsk_ring_prod *tx; + struct xsk_ctx *ctx; + struct xsk_socket_config config; + int fd; +}; +struct xsk_socket_info { + struct xsk_ring_cons rx; + struct xsk_ring_prod tx; + struct xsk_umem_info *umem; + struct xsk_socket *xsk; + struct xsk_ring_stats ring_stats; + struct xsk_app_stats app_stats; + struct xsk_driver_stats drv_stats; + u_int32_t outstanding_tx; +}; +#endif /* HAVE_LIBXDP */ + struct sendpacket_s { tcpr_dir_t cache_dir; int open; @@ -140,12 +206,65 @@ struct sendpacket_s { #ifdef HAVE_TX_RING txring_t *tx_ring; #endif +#endif +#ifdef HAVE_LIBXDP + struct xsk_socket_info *xsk_info; + struct xsk_umem_info *umem_info; + unsigned int batch_size; + unsigned int pckt_count; + int frame_size; + unsigned int tx_idx; + int tx_size; #endif bool abort; }; - typedef struct sendpacket_s sendpacket_t; +#ifdef HAVE_LIBXDP +struct xsk_umem_info * +create_umem_area(int nb_of_frames, int frame_size, int nb_of_completion_queue_descs, int nb_of_fill_queue_descs); +struct xsk_socket_info *create_xsk_socket(struct xsk_umem_info *umem, + int nb_of_tx_queue_desc, + int nb_of_rx_queue_desc, + const char *device, + u_int32_t queue_id, + char *errbuf); +static inline void +gen_eth_frame(struct xsk_umem_info *umem, u_int64_t addr, u_char *pkt_data, COUNTER pkt_size) +{ + memcpy(xsk_umem__get_data(umem->buffer, addr), pkt_data, pkt_size); +} + +static inline void +kick_tx(struct xsk_socket_info *xsk) +{ + int ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0); + if (ret >= 0 || errno == ENOBUFS || errno == EAGAIN || errno == EBUSY || errno == ENETDOWN) { + return; + } + printf("%s\n", "Packet sending exited with error!"); + exit (1); +} + +static inline void +complete_tx_only(sendpacket_t *sp) +{ + u_int32_t completion_idx = 0; + if (sp->xsk_info->outstanding_tx == 0) { + return; + } + if (xsk_ring_prod__needs_wakeup(&(sp->xsk_info->tx))) { + sp->xsk_info->app_stats.tx_wakeup_sendtos++; + kick_tx(sp->xsk_info); + } + unsigned int rcvd = xsk_ring_cons__peek(&sp->xsk_info->umem->cq, sp->pckt_count, &completion_idx); + if (rcvd > 0) { + xsk_ring_cons__release(&sp->xsk_info->umem->cq, rcvd); + sp->xsk_info->outstanding_tx -= rcvd; + } +} +#endif /* HAVE_LIBXDP */ + int sendpacket(sendpacket_t *, const u_char *, size_t, struct pcap_pkthdr *); void sendpacket_close(sendpacket_t *); char *sendpacket_geterr(sendpacket_t *); diff --git a/src/common/services.c b/src/common/services.c index 76b92599f..06a086952 100644 --- a/src/common/services.c +++ b/src/common/services.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/services.h b/src/common/services.h index a632df23a..022d9208e 100644 --- a/src/common/services.h +++ b/src/common/services.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/tcpdump.c b/src/common/tcpdump.c index 637af8399..4e53a08e2 100644 --- a/src/common/tcpdump.c +++ b/src/common/tcpdump.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -75,7 +75,7 @@ tcpdump_print(tcpdump_t *tcpdump, struct pcap_pkthdr *pkthdr, const u_char *data /* convert header to file-format packet header */ actual_pkthdr.ts.ts_sec = (uint32_t)pkthdr->ts.tv_sec; - actual_pkthdr.ts.ts_usec = (uint32_t)pkthdr->ts.tv_sec; + actual_pkthdr.ts.ts_usec = (uint32_t)(pkthdr->ts.tv_usec / PCAP_TSTAMP_US_TO_US_DIVISOR); actual_pkthdr.caplen = pkthdr->caplen; actual_pkthdr.len = pkthdr->len; diff --git a/src/common/tcpdump.h b/src/common/tcpdump.h index e5dcec12b..0dcbeba8a 100644 --- a/src/common/tcpdump.h +++ b/src/common/tcpdump.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/timer.c b/src/common/timer.c index 169ca65d2..305da90d4 100755 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -22,7 +22,7 @@ #include "config.h" #include -/* Miscellaneous timeval routines */ +/* Miscellaneous timeval/timespec routines */ /* Divide tvs by div, storing the result in tvs */ void @@ -39,7 +39,20 @@ timesdiv_float(struct timespec *tvs, float div) } void -init_timestamp(timestamp_t *ctx) +init_timestamp(struct timespec *timestamp) { - timerclear(ctx); + timesclear(timestamp); +} + +int +get_current_time(struct timespec *ts) +{ +#if defined CLOCK_MONOTONIC || defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L + return clock_gettime(CLOCK_MONOTONIC, ts); +#else + struct timeval tv; + int success = gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, ts); + return success; +#endif } diff --git a/src/common/timer.h b/src/common/timer.h index db5bc1744..f84ce8874 100755 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -112,6 +112,33 @@ void timesdiv_float(struct timespec *tvs, float div); } while (0) #endif +/* add tvp and uvp and store in vvp */ +#ifndef timeradd_timespec +#define timeradd_timespec(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_nsec = (tvp)->tv_nsec + (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec >= 1000000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_nsec -= 1000000000; \ + } \ + } while (0) +#endif + +/* add tvp and uvp and store in vvp */ +#ifndef timeradd_timeval_timespec +#define timeradd_timeval_timespec(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_nsec = (tvp)->tv_nsec + (uvp)->tv_usec * 1000; \ + if ((vvp)->tv_nsec >= 1000000000) { \ + int seconds = (vvp)->tv_nsec % 1000000000; \ + (vvp)->tv_sec += seconds; \ + (vvp)->tv_nsec -= 1000000000 * seconds; \ + } \ + } while (0) +#endif + /* subtract uvp from tvp and store in vvp */ #ifndef timersub #define timersub(tvp, uvp, vvp) \ @@ -150,4 +177,5 @@ void timesdiv_float(struct timespec *tvs, float div); typedef struct timeval timestamp_t; -void init_timestamp(timestamp_t *ctx); +void init_timestamp(struct timespec *timestamp); +int get_current_time(struct timespec *timestamp); diff --git a/src/common/utils.c b/src/common/utils.c index 6aed5b327..affb2e1e7 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -97,6 +97,17 @@ our_safe_strdup(const char *str, const char *funcname, int line, const char *fil return newstr; } +pcap_t* +tcpr_pcap_open(const char *path, char *ebuf) +{ +#ifdef HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION + return pcap_open_offline_with_tstamp_precision(path, PCAP_TSTAMP_PRECISION_NANO, ebuf); +#else + return pcap_open_offline(path, ebuf); +#endif +} + + /** * calls free and sets to NULL. */ @@ -211,7 +222,7 @@ our_safe_pcap_next_ex(pcap_t *pcap, void packet_stats(const tcpreplay_stats_t *stats) { - struct timeval diff; + struct timespec diff; COUNTER diff_us; COUNTER bytes_sec = 0; u_int32_t bytes_sec_10ths = 0; @@ -221,8 +232,8 @@ packet_stats(const tcpreplay_stats_t *stats) COUNTER pkts_sec = 0; u_int32_t pkts_sec_100ths = 0; - timersub(&stats->end_time, &stats->start_time, &diff); - diff_us = TIMEVAL_TO_MICROSEC(&diff); + timessub(&stats->end_time, &stats->start_time, &diff); + diff_us = TIMESPEC_TO_MICROSEC(&diff); if (diff_us && stats->pkts_sent && stats->bytes_sent) { COUNTER bytes_sec_X10; @@ -251,18 +262,19 @@ packet_stats(const tcpreplay_stats_t *stats) pkts_sec_100ths = pkts_sec_X100 % 100; } - if (diff_us >= 1000 * 1000) + if (diff_us >= 1000 * 1000) { printf("Actual: " COUNTER_SPEC " packets (" COUNTER_SPEC " bytes) sent in %zd.%02zd seconds\n", stats->pkts_sent, stats->bytes_sent, (ssize_t)diff.tv_sec, - (ssize_t)(diff.tv_usec / (10 * 1000))); - else + (ssize_t)(diff.tv_nsec / (10 * 1000000))); + } else { printf("Actual: " COUNTER_SPEC " packets (" COUNTER_SPEC " bytes) sent in %zd.%06zd seconds\n", stats->pkts_sent, stats->bytes_sent, (ssize_t)diff.tv_sec, - (ssize_t)diff.tv_usec); + (ssize_t)diff.tv_nsec / 1000); + } if (mb_sec >= 1) printf("Rated: %llu.%1u Bps, %llu.%02u Mbps, %llu.%02u pps\n", @@ -295,7 +307,7 @@ packet_stats(const tcpreplay_stats_t *stats) * @return: string containing date, or -1 on error */ int -format_date_time(struct timeval *when, char *buf, size_t len) +format_date_time(struct timespec *when, char *buf, size_t len) { struct tm *tm; char tmp[64]; @@ -306,8 +318,8 @@ format_date_time(struct timeval *when, char *buf, size_t len) if (!tm) return -1; - strftime(tmp, sizeof tmp, "%Y-%m-%d %H:%M:%S.%%06u", tm); - return snprintf(buf, len, tmp, when->tv_usec); + strftime(tmp, sizeof tmp, "%Y-%m-%d %H:%M:%S.%%09u", tm); + return snprintf(buf, len, tmp, when->tv_nsec); } /** diff --git a/src/common/utils.h b/src/common/utils.h index c758f4723..9938912be 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -29,11 +29,11 @@ typedef struct { COUNTER bytes_sent; COUNTER pkts_sent; COUNTER failed; - struct timeval start_time; - struct timeval time_delta; - struct timeval end_time; - struct timeval pkt_ts_delta; - struct timeval last_print; + struct timespec start_time; + struct timespec time_delta; + struct timespec end_time; + struct timespec pkt_ts_delta; + struct timespec last_print; COUNTER flow_non_flow_packets; COUNTER flows; COUNTER flows_unique; @@ -44,9 +44,10 @@ typedef struct { int read_hexstring(const char *l2string, u_char *hex, int hexlen); void packet_stats(const tcpreplay_stats_t *stats); -int format_date_time(struct timeval *when, char *buf, size_t len); +int format_date_time(struct timespec *when, char *buf, size_t len); uint32_t tcpr_random(uint32_t *seed); void restore_stdin(void); +pcap_t* tcpr_pcap_open(const char *path, char *ebuf); /* our "safe" implimentations of functions which allocate memory */ #define safe_malloc(x) our_safe_malloc(x, __FUNCTION__, __LINE__, __FILE__) diff --git a/src/common/xX.c b/src/common/xX.c index 35528832f..be98943e8 100644 --- a/src/common/xX.c +++ b/src/common/xX.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/common/xX.h b/src/common/xX.h index b8a714e26..fa2581008 100644 --- a/src/common/xX.h +++ b/src/common/xX.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/defines.h.in b/src/defines.h.in index 6b651398a..862149433 100644 --- a/src/defines.h.in +++ b/src/defines.h.in @@ -48,6 +48,22 @@ #define PCAP_DONT_INCLUDE_PCAP_BPF_H 1 #endif +#ifdef HAVE_LIBBPF +#undef HAVE_BPF +#include +#include +#define PCAP_DONT_INCLUDE_PCAP_BPF_H 1 + +struct bpf_program { +char dummy[0]; +}; + +#endif + +#ifdef HAVE_LIBXDP +#include +#endif + #if defined INCLUDE_PCAP_BPF_H_FILE && !defined PCAP_DONT_INCLUDE_PCAP_BPF_H #include <@INCLUDE_PCAP_BPF_HEADER@> #define PCAP_DONT_INCLUDE_PCAP_BPF_H 1 /* don't re-include it in pcap.h */ @@ -86,7 +102,7 @@ #define COUNTER unsigned long #define COUNTER_SPEC "%lu" #endif -#define COUNTER_OVERFLOW_RISK (((COUNTER)~0) >> 20) +#define COUNTER_OVERFLOW_RISK (((COUNTER)~0) >> 23) #include #include @@ -101,6 +117,7 @@ typedef struct tcpr_icmpv6_hdr icmpv6_hdr_t; typedef struct tcpr_ethernet_hdr eth_hdr_t; typedef struct tcpr_802_1q_hdr vlan_hdr_t; typedef struct sll_header sll_hdr_t; +typedef struct sll2_header sll2_hdr_t; typedef struct tcpr_arp_hdr arp_hdr_t; typedef struct tcpr_dnsv4_hdr dnsv4_hdr_t; @@ -298,10 +315,9 @@ typedef u_int8_t uint8_t typedef u_int16_t uint16_t typedef u_int32_t uint32_t #define MICROSEC_TO_SEC(x) (x / 1000000) #define NANOSEC_TO_SEC(x) ((u_int64_t)x / 1000000000) -#define TIMEVAL_TO_MILLISEC(x) (((x)->tv_sec * 1000) + ((x)->tv_usec / 1000)) -#define TIMEVAL_TO_MICROSEC(x) (((x)->tv_sec * 1000000) + (x)->tv_usec) -#define TIMEVAL_TO_NANOSEC(x) ((u_int64_t)((x)->tv_sec * 1000000000) + ((u_int64_t)(x)->tv_usec * 1000)) -#define TIMSTAMP_TO_MICROSEC(x) (TIMEVAL_TO_MICROSEC(x)) +#define TIMEVAL_TO_MILLISEC(x) (((x)->tv_sec * 1000) + ((x)->tv_usec / 1000)) +#define TIMEVAL_TO_MICROSEC(x) (((x)->tv_sec * 1000000) + (x)->tv_usec) +#define TIMEVAL_TO_NANOSEC(x) ((u_int64_t)((x)->tv_sec * 1000000000) + ((u_int64_t)(x)->tv_usec * 1000)) #define MILLISEC_TO_TIMEVAL(x, tv) \ do { \ @@ -343,7 +359,24 @@ typedef u_int8_t uint8_t typedef u_int16_t uint16_t typedef u_int32_t uint32_t (a)->tv_nsec = (b)->tv_nsec; \ } while (0) -/* +/* libpcap that supports it, puts nanosecond values in tv_usec when pcap file is read with nanosec precision, + * and so tv_usec is directly copied to tv_nsec. + * But older versions do that do not support nanosecond precision need to multiply tv_usec by 1000 to convert + * to tv_nsec. + */ +#define PCAP_TIMEVAL_TO_TIMESPEC_SET(a, b) \ + do { \ + (b)->tv_sec = (a)->tv_sec; \ + (b)->tv_nsec = (a)->tv_usec * PCAP_TSTAMP_US_TO_NS_MULTIPLIER; \ + } while(0) + +#define PCAP_TIMEVAL_TO_TIMEVAL_SET(a, b) \ + do { \ + (b)->tv_sec = (a)->tv_sec; \ + (b)->tv_usec = (a)->tv_usec / PCAP_TSTAMP_US_TO_US_DIVISOR; \ + } while(0) + +/* * Help suppress some compiler warnings * No problem if variable is actually used */ diff --git a/src/fragroute/fragroute.c b/src/fragroute/fragroute.c index b7edd2b02..6812c602d 100644 --- a/src/fragroute/fragroute.c +++ b/src/fragroute/fragroute.c @@ -3,7 +3,7 @@ * * Copyright (c) 2001 Dug Song * Copyright (c) 2007-2008 Aaron Turner. - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * $Id$ */ diff --git a/src/fragroute/fragroute.h b/src/fragroute/fragroute.h index 2931ad653..f7460a19f 100644 --- a/src/fragroute/fragroute.h +++ b/src/fragroute/fragroute.h @@ -3,7 +3,7 @@ /* * Copyright (c) 2001 Dug Song * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/replay.c b/src/replay.c index c39665268..db4724671 100644 --- a/src/replay.c +++ b/src/replay.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -117,7 +117,7 @@ replay_file(tcpreplay_t *ctx, int idx) /* read from pcap file if we haven't cached things yet */ if (!ctx->options->preload_pcap) { - if ((pcap = pcap_open_offline(path, ebuf)) == NULL) { + if ((pcap = tcpr_pcap_open(path, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } @@ -133,7 +133,7 @@ replay_file(tcpreplay_t *ctx, int idx) } else { if (!ctx->options->file_cache[idx].cached) { - if ((pcap = pcap_open_offline(path, ebuf)) == NULL) { + if ((pcap = tcpr_pcap_open(path, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } @@ -145,7 +145,7 @@ replay_file(tcpreplay_t *ctx, int idx) if (ctx->options->verbose) { /* in cache mode, we may not have opened the file */ if (pcap == NULL) - if ((pcap = pcap_open_offline(path, ebuf)) == NULL) { + if ((pcap = tcpr_pcap_open(path, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } @@ -214,26 +214,26 @@ replay_two_files(tcpreplay_t *ctx, int idx1, int idx2) /* read from first pcap file if we haven't cached things yet */ if (!ctx->options->preload_pcap) { - if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) { + if ((pcap1 = tcpr_pcap_open(path1, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1); - if ((pcap2 = pcap_open_offline(path2, ebuf)) == NULL) { + if ((pcap2 = tcpr_pcap_open(path2, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx2].dlt = pcap_datalink(pcap2); } else { if (!ctx->options->file_cache[idx1].cached) { - if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) { + if ((pcap1 = tcpr_pcap_open(path1, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1); } if (!ctx->options->file_cache[idx2].cached) { - if ((pcap2 = pcap_open_offline(path2, ebuf)) == NULL) { + if ((pcap2 = tcpr_pcap_open(path2, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } @@ -293,7 +293,7 @@ replay_two_files(tcpreplay_t *ctx, int idx1, int idx2) if (ctx->options->verbose) { /* in cache mode, we may not have opened the file */ if (pcap1 == NULL) { - if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) { + if ((pcap1 = tcpr_pcap_open(path1, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } diff --git a/src/replay.h b/src/replay.h index 4a4becdf8..3f8c4f598 100644 --- a/src/replay.h +++ b/src/replay.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/send_packets.c b/src/send_packets.c index a09d7d5e4..fd0576344 100644 --- a/src/send_packets.c +++ b/src/send_packets.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -57,17 +57,20 @@ extern tcpedit_t *tcpedit; #include "sleep.h" static void calc_sleep_time(tcpreplay_t *ctx, - struct timeval *pkt_ts_delta, - struct timeval *time_delta, + struct timespec *pkt_time, + struct timespec *last, COUNTER len, sendpacket_t *sp, COUNTER counter, - timestamp_t *sent_timestamp, + struct timespec *sent_timestamp, COUNTER start_us, COUNTER *skip_length); -static void tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp _U_, struct timespec *nap_this_time, struct timeval *now); -static u_char * -get_next_packet(tcpreplay_t *ctx, pcap_t *pcap, struct pcap_pkthdr *pkthdr, int file_idx, packet_cache_t **prev_packet); +static void tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp _U_, struct timespec *nap_this_time, struct timespec *now); +static u_char *get_next_packet(tcpreplay_opt_t *options, + pcap_t *pcap, + struct pcap_pkthdr *pkthdr, + int file_idx, + packet_cache_t **prev_packet); static uint32_t get_user_count(tcpreplay_t *ctx, sendpacket_t *sp, COUNTER counter); #ifdef HAVE_NETMAP @@ -227,9 +230,11 @@ update_flow_stats(tcpreplay_t *ctx, sendpacket_t *sp, const struct pcap_pkthdr *pkthdr, const u_char *pktdata, - int datalink) + int datalink, + COUNTER packetnum) { - flow_entry_type_t res = flow_decode(ctx->flow_hash_table, pkthdr, pktdata, datalink, ctx->options->flow_expiry); + flow_entry_type_t res = + flow_decode(ctx->flow_hash_table, pkthdr, pktdata, datalink, ctx->options->flow_expiry, packetnum); switch (res) { case FLOW_ENTRY_NEW: @@ -296,14 +301,17 @@ preload_pcap_file(tcpreplay_t *ctx, int idx) if (close(1) == -1) warnx("unable to close stdin: %s", strerror(errno)); - if ((pcap = pcap_open_offline(path, ebuf)) == NULL) + if ((pcap = tcpr_pcap_open(path, ebuf)) == NULL) errx(-1, "Error opening pcap file: %s", ebuf); dlt = pcap_datalink(pcap); + COUNTER packetnum = 0; /* loop through the pcap. get_next_packet() builds the cache for us! */ - while ((pktdata = get_next_packet(ctx, pcap, &pkthdr, idx, prev_packet)) != NULL) { - if (options->flow_stats) - update_flow_stats(ctx, NULL, &pkthdr, pktdata, dlt); + while ((pktdata = get_next_packet(options, pcap, &pkthdr, idx, prev_packet)) != NULL) { + if (options->flow_stats) { + ++packetnum; + update_flow_stats(ctx, NULL, &pkthdr, pktdata, dlt, packetnum); + } } /* mark this file as cached */ @@ -332,7 +340,7 @@ increment_iteration(tcpreplay_t *ctx) void send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) { - struct timeval print_delta, now, last_pkt_ts; + struct timespec now, print_delta, last_pkt_ts; tcpreplay_opt_t *options = ctx->options; tcpreplay_stats_t *stats = &ctx->stats; COUNTER packetnum = 0; @@ -353,10 +361,11 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) bool top_speed = (options->speed.mode == speed_topspeed || (options->speed.mode == speed_mbpsrate && options->speed.speed == 0)); bool now_is_now = true; + bool read_next_packet = true; // used for LIBXDP batch packet processing with cached packets - gettimeofday(&now, NULL); - if (!timerisset(&stats->start_time)) { - TIMEVAL_SET(&stats->start_time, &now); + get_current_time(&now); + if (!timesisset(&stats->start_time)) { + TIMESPEC_SET(&stats->start_time, &now); if (ctx->options->stats >= 0) { char buf[64]; if (format_date_time(&stats->start_time, buf, sizeof(buf)) > 0) @@ -365,9 +374,9 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) } ctx->skip_packets = 0; - timerclear(&last_pkt_ts); + timesclear(&last_pkt_ts); if (options->limit_time > 0) - end_us = TIMEVAL_TO_MICROSEC(&stats->start_time) + SEC_TO_MICROSEC(options->limit_time); + end_us = TIMESPEC_TO_MICROSEC(&stats->start_time) + SEC_TO_MICROSEC(options->limit_time); else end_us = 0; @@ -381,7 +390,10 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) * Keep sending while we have packets or until * we've sent enough packets */ - while (!ctx->abort && (pktdata = get_next_packet(ctx, pcap, &pkthdr, idx, prev_packet)) != NULL) { + while (!ctx->abort && read_next_packet && + (pktdata = get_next_packet(options, pcap, &pkthdr, idx, prev_packet)) != NULL) { + struct timespec pkthdr_ts; + PCAP_TIMEVAL_TO_TIMESPEC_SET(&pkthdr.ts, &pkthdr_ts); now_is_now = false; packetnum++; #if defined TCPREPLAY || defined TCPREPLAY_EDIT @@ -422,7 +434,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) /* update flow stats */ if (options->flow_stats && !preload) - update_flow_stats(ctx, options->cache_packets ? sp : NULL, &pkthdr, pktdata, datalink); + update_flow_stats(ctx, options->cache_packets ? sp : NULL, &pkthdr, pktdata, datalink, packetnum); /* * this accelerator improves performance by avoiding expensive @@ -438,25 +450,25 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) * time stamping is expensive, but now is the * time to do it. */ - dbgx(4, "This packet time: " TIMEVAL_FORMAT, pkthdr.ts.tv_sec, pkthdr.ts.tv_usec); + dbgx(4, "This packet time: " TIMESPEC_FORMAT, pkthdr_ts.tv_sec, pkthdr_ts.tv_nsec); skip_length = 0; ctx->skip_packets = 0; if (options->speed.mode == speed_multiplier) { - if (!timerisset(&last_pkt_ts)) { - TIMEVAL_SET(&last_pkt_ts, &pkthdr.ts); - } else if (timercmp(&pkthdr.ts, &last_pkt_ts, >)) { - struct timeval delta; - - timersub(&pkthdr.ts, &last_pkt_ts, &delta); - timeradd(&stats->pkt_ts_delta, &delta, &stats->pkt_ts_delta); - TIMEVAL_SET(&last_pkt_ts, &pkthdr.ts); + if (!timesisset(&last_pkt_ts)) { + TIMESPEC_SET(&last_pkt_ts, &pkthdr_ts); + } else if (timescmp(&pkthdr_ts, &last_pkt_ts, >)) { + struct timespec delta; + + timessub(&pkthdr_ts, &last_pkt_ts, &delta); + timeradd_timespec(&stats->pkt_ts_delta, &delta, &stats->pkt_ts_delta); + TIMESPEC_SET(&last_pkt_ts, &pkthdr_ts); } } if (!top_speed) { now_is_now = true; - gettimeofday(&now, NULL); + get_current_time(&now); } /* @@ -472,7 +484,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) sp, packetnum, &stats->end_time, - TIMEVAL_TO_MICROSEC(&stats->start_time), + TIMESPEC_TO_NANOSEC(&stats->start_time), &skip_length); /* @@ -481,14 +493,24 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) * A number of 3rd party tools generate bad timestamps which go backwards * in time. Hence, don't update the "last" unless pkthdr.ts > last */ - if (timercmp(&stats->time_delta, &stats->pkt_ts_delta, <)) - TIMEVAL_SET(&stats->time_delta, &stats->pkt_ts_delta); + if (timescmp(&stats->time_delta, &stats->pkt_ts_delta, <)) + TIMESPEC_SET(&stats->time_delta, &stats->pkt_ts_delta); /* * we know how long to sleep between sends, now do it. */ - if (!top_speed) + if (!top_speed) { +#ifndef HAVE_LIBXDP tcpr_sleep(ctx, sp, &ctx->nap, &now); +#else + if (sp->handle_type != SP_TYPE_LIBXDP) { + tcpr_sleep(ctx, sp, &ctx->nap, &now); + } else if (sp->batch_size == 1) { + // In case of LIBXDP packet processing waiting only makes sense when batch size is one + tcpr_sleep(ctx, sp, &ctx->nap, &now); + } +#endif + } } #ifdef ENABLE_VERBOSE @@ -497,6 +519,18 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) tcpdump_print(options->tcpdump, &pkthdr, pktdata); #endif +#ifdef HAVE_LIBXDP + if (sp->handle_type == SP_TYPE_LIBXDP) { + /* Reserve frames for the batc h*/ + while (xsk_ring_prod__reserve(&(sp->xsk_info->tx), sp->batch_size, &sp->tx_idx) < sp->batch_size) { + complete_tx_only(sp); + } + /* The first packet is already in memory */ + prepare_first_element_of_batch(ctx, &packetnum, pktdata, pkthdr.len); + /* Read more packets and prepare batch */ + prepare_remaining_elements_of_batch(ctx, &packetnum, &read_next_packet, pcap, &idx, pkthdr, prev_packet); + } +#endif dbgx(2, "Sending packet #" COUNTER_SPEC, packetnum); /* write packet out on network */ if (sendpacket(sp, pktdata, pktlen, &pkthdr) < (int)pktlen) { @@ -507,25 +541,29 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) /* * Mark the time when we sent the last packet */ - TIMEVAL_SET(&stats->end_time, &now); + TIMESPEC_SET(&stats->end_time, &now); #ifdef TIMESTAMP_TRACE add_timestamp_trace_entry(pktlen, &stats->end_time, skip_length); #endif stats->pkts_sent++; +#ifndef HAVE_LIBXDP stats->bytes_sent += pktlen; - +#else + if (sp->handle_type != SP_TYPE_LIBXDP) + stats->bytes_sent += pktlen; +#endif /* print stats during the run? */ if (options->stats > 0) { - if (!timerisset(&stats->last_print)) { - TIMEVAL_SET(&stats->last_print, &now); + if (!timesisset(&stats->last_print)) { + TIMESPEC_SET(&stats->last_print, &now); } else { - timersub(&now, &stats->last_print, &print_delta); + timessub(&now, &stats->last_print, &print_delta); if (print_delta.tv_sec >= options->stats) { - TIMEVAL_SET(&stats->end_time, &now); + TIMESPEC_SET(&stats->end_time, &now); packet_stats(stats); - TIMEVAL_SET(&stats->last_print, &now); + TIMESPEC_SET(&stats->last_print, &now); } } } @@ -537,7 +575,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) } #endif /* stop sending based on the duration limit... */ - if ((end_us > 0 && (COUNTER)TIMEVAL_TO_MICROSEC(&now) > end_us) || + if ((end_us > 0 && (COUNTER)TIMESPEC_TO_MICROSEC(&now) > end_us) || /* ... or stop sending based on the limit -L? */ (limit_send > 0 && stats->pkts_sent >= limit_send)) { ctx->abort = true; @@ -549,20 +587,20 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) if (options->netmap && (ctx->abort || options->loop == 1)) { while (ctx->intf1 && !netmap_tx_queues_empty(ctx->intf1)) { now_is_now = true; - gettimeofday(&now, NULL); + get_current_time(&now); } while (ctx->intf2 && !netmap_tx_queues_empty(ctx->intf2)) { now_is_now = true; - gettimeofday(&now, NULL); + get_current_time(&now); } } #endif /* HAVE_NETMAP */ if (!now_is_now) - gettimeofday(&now, NULL); + get_current_time(&now); - TIMEVAL_SET(&stats->end_time, &now); + TIMESPEC_SET(&stats->end_time, &now); increment_iteration(ctx); } @@ -574,7 +612,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx) void send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *pcap2, int cache_file_idx2) { - struct timeval print_delta, now, last_pkt_ts; + struct timespec now, print_delta, last_pkt_ts; tcpreplay_opt_t *options = ctx->options; tcpreplay_stats_t *stats = &ctx->stats; COUNTER packetnum = 0; @@ -594,9 +632,9 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * (options->speed.mode == speed_mbpsrate && options->speed.speed == 0)); bool now_is_now = true; - gettimeofday(&now, NULL); - if (!timerisset(&stats->start_time)) { - TIMEVAL_SET(&stats->start_time, &now); + get_current_time(&now); + if (!timesisset(&stats->start_time)) { + TIMESPEC_SET(&stats->start_time, &now); if (ctx->options->stats >= 0) { char buf[64]; if (format_date_time(&stats->start_time, buf, sizeof(buf)) > 0) @@ -605,9 +643,9 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * } ctx->skip_packets = 0; - timerclear(&last_pkt_ts); + timesclear(&last_pkt_ts); if (options->limit_time > 0) - end_us = TIMEVAL_TO_MICROSEC(&stats->start_time) + SEC_TO_MICROSEC(options->limit_time); + end_us = TIMESPEC_TO_MICROSEC(&stats->start_time) + SEC_TO_MICROSEC(options->limit_time); else end_us = 0; @@ -619,8 +657,8 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * prev_packet2 = NULL; } - pktdata1 = get_next_packet(ctx, pcap1, &pkthdr1, cache_file_idx1, prev_packet1); - pktdata2 = get_next_packet(ctx, pcap2, &pkthdr2, cache_file_idx2, prev_packet2); + pktdata1 = get_next_packet(options, pcap1, &pkthdr1, cache_file_idx1, prev_packet1); + pktdata2 = get_next_packet(options, pcap2, &pkthdr2, cache_file_idx2, prev_packet2); /* MAIN LOOP * Keep sending while we have packets or until @@ -684,7 +722,7 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * /* update flow stats */ if (options->flow_stats && !options->file_cache[cache_file_idx].cached) - update_flow_stats(ctx, sp, pkthdr_ptr, pktdata, datalink); + update_flow_stats(ctx, sp, pkthdr_ptr, pktdata, datalink, packetnum); /* * this accelerator improves performance by avoiding expensive @@ -705,22 +743,24 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * ctx->skip_packets = 0; if (options->speed.mode == speed_multiplier) { - if (!timerisset(&last_pkt_ts)) { - TIMEVAL_SET(&last_pkt_ts, &pkthdr_ptr->ts); - } else if (timercmp(&pkthdr_ptr->ts, &last_pkt_ts, >)) { - struct timeval delta; - - timersub(&pkthdr_ptr->ts, &last_pkt_ts, &delta); - timeradd(&stats->pkt_ts_delta, &delta, &stats->pkt_ts_delta); - TIMEVAL_SET(&last_pkt_ts, &pkthdr_ptr->ts); + struct timespec pkthdr_ts; + PCAP_TIMEVAL_TO_TIMESPEC_SET(&pkthdr_ptr->ts, &pkthdr_ts); + if (!timesisset(&last_pkt_ts)) { + PCAP_TIMEVAL_TO_TIMESPEC_SET(&pkthdr_ptr->ts, &last_pkt_ts); + } else if (timescmp(&pkthdr_ts, &last_pkt_ts, >)) { + struct timespec delta; + + timessub(&pkthdr_ts, &last_pkt_ts, &delta); + timeradd_timespec(&stats->pkt_ts_delta, &delta, &stats->pkt_ts_delta); + TIMESPEC_SET(&last_pkt_ts, &pkthdr_ts); } - if (!timerisset(&stats->time_delta)) - TIMEVAL_SET(&stats->pkt_ts_delta, &stats->pkt_ts_delta); + if (!timesisset(&stats->time_delta)) + TIMESPEC_SET(&stats->pkt_ts_delta, &stats->pkt_ts_delta); } if (!top_speed) { - gettimeofday(&now, NULL); + get_current_time(&now); now_is_now = true; } @@ -737,7 +777,7 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * sp, packetnum, &stats->end_time, - TIMEVAL_TO_MICROSEC(&stats->start_time), + TIMESPEC_TO_NANOSEC(&stats->start_time), &skip_length); /* @@ -746,8 +786,8 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * * A number of 3rd party tools generate bad timestamps which go backwards * in time. Hence, don't update the "last" unless pkthdr_ptr->ts > last */ - if (timercmp(&stats->time_delta, &stats->pkt_ts_delta, <)) - TIMEVAL_SET(&stats->time_delta, &stats->pkt_ts_delta); + if (timescmp(&stats->time_delta, &stats->pkt_ts_delta, <)) + TIMESPEC_SET(&stats->time_delta, &stats->pkt_ts_delta); /* * we know how long to sleep between sends, now do it. @@ -772,21 +812,21 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * /* * Mark the time when we sent the last packet */ - TIMEVAL_SET(&stats->end_time, &now); + TIMESPEC_SET(&stats->end_time, &now); ++stats->pkts_sent; stats->bytes_sent += pktlen; /* print stats during the run? */ if (options->stats > 0) { - if (!timerisset(&stats->last_print)) { - TIMEVAL_SET(&stats->last_print, &now); + if (!timesisset(&stats->last_print)) { + TIMESPEC_SET(&stats->last_print, &now); } else { - timersub(&now, &stats->last_print, &print_delta); + timessub(&now, &stats->last_print, &print_delta); if (print_delta.tv_sec >= options->stats) { - TIMEVAL_SET(&stats->end_time, &now); + TIMESPEC_SET(&stats->end_time, &now); packet_stats(stats); - TIMEVAL_SET(&stats->last_print, &now); + TIMESPEC_SET(&stats->last_print, &now); } } } @@ -800,13 +840,13 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * /* get the next packet for this file handle depending on which we last used */ if (sp == ctx->intf2) { - pktdata2 = get_next_packet(ctx, pcap2, &pkthdr2, cache_file_idx2, prev_packet2); + pktdata2 = get_next_packet(options, pcap2, &pkthdr2, cache_file_idx2, prev_packet2); } else { - pktdata1 = get_next_packet(ctx, pcap1, &pkthdr1, cache_file_idx1, prev_packet1); + pktdata1 = get_next_packet(options, pcap1, &pkthdr1, cache_file_idx1, prev_packet1); } /* stop sending based on the duration limit... */ - if ((end_us > 0 && (COUNTER)TIMEVAL_TO_MICROSEC(&now) > end_us) || + if ((end_us > 0 && (COUNTER)TIMESPEC_TO_MICROSEC(&now) > end_us) || /* ... or stop sending based on the limit -L? */ (limit_send > 0 && stats->pkts_sent >= limit_send)) { ctx->abort = true; @@ -817,21 +857,21 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * /* when completing test, wait until the last packet is sent */ if (options->netmap && (ctx->abort || options->loop == 1)) { while (ctx->intf1 && !netmap_tx_queues_empty(ctx->intf1)) { - gettimeofday(&now, NULL); + get_current_time(&now); now_is_now = true; } while (ctx->intf2 && !netmap_tx_queues_empty(ctx->intf2)) { - gettimeofday(&now, NULL); + get_current_time(&now); now_is_now = true; } } #endif /* HAVE_NETMAP */ if (!now_is_now) - gettimeofday(&now, NULL); + get_current_time(&now); - TIMEVAL_SET(&stats->end_time, &now); + TIMESPEC_SET(&stats->end_time, &now); increment_iteration(ctx); } @@ -845,9 +885,8 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t * * will be updated as new entries are added (or retrieved) from the cache list. */ u_char * -get_next_packet(tcpreplay_t *ctx, pcap_t *pcap, struct pcap_pkthdr *pkthdr, int idx, packet_cache_t **prev_packet) +get_next_packet(tcpreplay_opt_t *options, pcap_t *pcap, struct pcap_pkthdr *pkthdr, int idx, packet_cache_t **prev_packet) { - tcpreplay_opt_t *options = ctx->options; u_char *pktdata = NULL; uint32_t pktlen; @@ -963,18 +1002,18 @@ cache_mode(tcpreplay_t *ctx, char *cachedata, COUNTER packet_num) */ static void calc_sleep_time(tcpreplay_t *ctx, - struct timeval *pkt_ts_delta, - struct timeval *time_delta, + struct timespec *pkt_ts_delta, + struct timespec *time_delta, COUNTER len, sendpacket_t *sp, COUNTER counter, - timestamp_t *sent_timestamp, - COUNTER start_us, + struct timespec *sent_timestamp, + COUNTER start_ns, COUNTER *skip_length) { tcpreplay_opt_t *options = ctx->options; - struct timeval nap_for; - COUNTER now_us; + struct timespec nap_for; + COUNTER now_ns; timesclear(&ctx->nap); @@ -998,10 +1037,10 @@ calc_sleep_time(tcpreplay_t *ctx, * Replay packets a factor of the time they were originally sent. * Make sure the packet is not late. */ - if (timercmp(pkt_ts_delta, time_delta, >)) { + if (timescmp(pkt_ts_delta, time_delta, >)) { /* pkt_time_delta has increased, so handle normally */ - timersub(pkt_ts_delta, time_delta, &nap_for); - TIMEVAL_TO_TIMESPEC(&nap_for, &ctx->nap); + timessub(pkt_ts_delta, time_delta, &nap_for); + TIMESPEC_SET(&ctx->nap, &nap_for); dbgx(3, "original packet delta time: " TIMESPEC_FORMAT, ctx->nap.tv_sec, ctx->nap.tv_nsec); timesdiv_float(&ctx->nap, options->speed.multiplier); dbgx(3, "original packet delta/div: " TIMESPEC_FORMAT, ctx->nap.tv_sec, ctx->nap.tv_nsec); @@ -1013,31 +1052,31 @@ calc_sleep_time(tcpreplay_t *ctx, * Ignore the time supplied by the capture file and send data at * a constant 'rate' (bytes per second). */ - now_us = TIMSTAMP_TO_MICROSEC(sent_timestamp); - if (now_us) { - COUNTER next_tx_us; + now_ns = TIMESPEC_TO_NANOSEC(sent_timestamp); + if (now_ns) { + COUNTER next_tx_ns; COUNTER bps = options->speed.speed; COUNTER bits_sent = ((ctx->stats.bytes_sent + len) * 8); - COUNTER tx_us = now_us - start_us; + COUNTER tx_ns = now_ns - start_ns; /* - * bits * 1000000 divided by bps = microseconds + * bits * 1000000000 divided by bps = nanosecond * * ensure there is no overflow in cases where bits_sent is very high */ - if (bits_sent > COUNTER_OVERFLOW_RISK && bps > 500000) - next_tx_us = (bits_sent * 1000) / bps * 1000; + if (bits_sent > COUNTER_OVERFLOW_RISK) + next_tx_ns = (bits_sent * 1000) / bps * 1000000; else - next_tx_us = (bits_sent * 1000000) / bps; + next_tx_ns = (bits_sent * 1000000000) / bps; - if (next_tx_us > tx_us) { - NANOSEC_TO_TIMESPEC((next_tx_us - tx_us) * 1000, &ctx->nap); - } else if (tx_us > next_tx_us) { - tx_us = now_us - start_us; - *skip_length = ((tx_us - next_tx_us) * bps) / 8000000; + if (next_tx_ns > tx_ns) { + NANOSEC_TO_TIMESPEC(next_tx_ns - tx_ns, &ctx->nap); + } else if (tx_ns > next_tx_ns) { + tx_ns = now_ns - start_ns; + *skip_length = ((tx_ns - next_tx_ns) * bps) / 8000000000; } - update_current_timestamp_trace_entry(ctx->stats.bytes_sent + (COUNTER)len, now_us, tx_us, next_tx_us); + update_current_timestamp_trace_entry(ctx->stats.bytes_sent + (COUNTER)len, now_ns, tx_ns, next_tx_ns); } dbgx(3, "packet size=" COUNTER_SPEC "\t\tnap=" TIMESPEC_FORMAT, len, ctx->nap.tv_sec, ctx->nap.tv_nsec); @@ -1048,12 +1087,12 @@ calc_sleep_time(tcpreplay_t *ctx, * Ignore the time supplied by the capture file and send data at * a constant rate (packets per second). */ - now_us = TIMSTAMP_TO_MICROSEC(sent_timestamp); - if (now_us) { - COUNTER next_tx_us; + now_ns = TIMESPEC_TO_NANOSEC(sent_timestamp); + if (now_ns) { + COUNTER next_tx_ns; COUNTER pph = ctx->options->speed.speed; COUNTER pkts_sent = ctx->stats.pkts_sent; - COUNTER tx_us = now_us - start_us; + COUNTER tx_ns = now_ns - start_ns; /* * packets * 1000000 divided by pps = microseconds * packets per sec (pps) = packets per hour / (60 * 60) @@ -1062,16 +1101,16 @@ calc_sleep_time(tcpreplay_t *ctx, * When active, adjusted calculation may add a bit of jitter. */ if ((pkts_sent < COUNTER_OVERFLOW_RISK)) - next_tx_us = (pkts_sent * 1000000) * (60 * 60) / pph; + next_tx_ns = (pkts_sent * 1000000000) * (60 * 60) / pph; else - next_tx_us = ((pkts_sent * 1000000) / pph) * (60 * 60); + next_tx_ns = ((pkts_sent * 1000000) / pph * 1000) * (60 * 60); - if (next_tx_us > tx_us) - NANOSEC_TO_TIMESPEC((next_tx_us - tx_us) * 1000, &ctx->nap); + if (next_tx_ns > tx_ns) + NANOSEC_TO_TIMESPEC(next_tx_ns - tx_ns, &ctx->nap); else ctx->skip_packets = options->speed.pps_multi; - update_current_timestamp_trace_entry(ctx->stats.bytes_sent + (COUNTER)len, now_us, tx_us, next_tx_us); + update_current_timestamp_trace_entry(ctx->stats.bytes_sent + (COUNTER)len, now_ns, tx_ns, next_tx_ns); } dbgx(3, @@ -1105,7 +1144,7 @@ calc_sleep_time(tcpreplay_t *ctx, } static void -tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp, struct timespec *nap_this_time, struct timeval *now) +tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp, struct timespec *nap_this_time, struct timespec *now) { tcpreplay_opt_t *options = ctx->options; bool flush = @@ -1215,3 +1254,78 @@ get_user_count(tcpreplay_t *ctx, sendpacket_t *sp, COUNTER counter) return (uint32_t)send; } + +#ifdef HAVE_LIBXDP +void +check_packet_fits_in_umem_frame(sendpacket_t *sp, int packet_len) +{ + if (packet_len > sp->frame_size) { + fprintf(stderr, + "ERROR: packet size cannot be larger than the size of an UMEM frame! Packet size: %i Frame size: %i\n", + packet_len, + sp->frame_size); + free_umem_and_xsk(sp); + exit(-1); + } +} + +void +fill_umem_with_data_and_set_xdp_desc(sendpacket_t *sp, int tx_idx, COUNTER umem_index, u_char *pktdata, int len) +{ + check_packet_fits_in_umem_frame(sp, len); + COUNTER umem_index_mod = (umem_index % sp->batch_size) * sp->frame_size; // packets are sent in batch, after each + // batch umem memory is reusable + gen_eth_frame(sp->umem_info, umem_index_mod, pktdata, len); + struct xdp_desc *xdp_desc = xsk_ring_prod__tx_desc(&(sp->xsk_info->tx), tx_idx); + xdp_desc->addr = (COUNTER)(umem_index_mod); + xdp_desc->len = len; +} + +void +prepare_first_element_of_batch(tcpreplay_t *ctx, COUNTER *packetnum, u_char *pktdata, u_int32_t len) +{ + sendpacket_t *sp = ctx->intf1; + tcpreplay_stats_t *stats = &ctx->stats; + fill_umem_with_data_and_set_xdp_desc(sp, sp->tx_idx, *packetnum - 1, pktdata, len); + sp->bytes_sent += len; + stats->bytes_sent += len; +} + +void +prepare_remaining_elements_of_batch(tcpreplay_t *ctx, + COUNTER *packetnum, + bool *read_next_packet, + pcap_t *pcap, + int *idx, + struct pcap_pkthdr pkthdr, + packet_cache_t **prev_packet) +{ + sendpacket_t *sp = ctx->intf1; + tcpreplay_stats_t *stats = &ctx->stats; + int datalink = ctx->options->file_cache[*idx].dlt; + bool preload = ctx->options->file_cache[*idx].cached; + u_char *pktdata = NULL; + unsigned int pckt_count = 1; + while (!ctx->abort && (pckt_count < sp->batch_size) && + (pktdata = get_next_packet(ctx->options, pcap, &pkthdr, *idx, prev_packet)) != NULL) { + fill_umem_with_data_and_set_xdp_desc(sp, sp->tx_idx + pckt_count, *packetnum, pktdata, pkthdr.len); + ++pckt_count; + ++*packetnum; + stats->bytes_sent += pkthdr.len; + sp->bytes_sent += pkthdr.len; + stats->pkts_sent++; + if (ctx->options->flow_stats && !preload) { + update_flow_stats(ctx, ctx->options->cache_packets ? sp : NULL, &pkthdr, pktdata, datalink, *packetnum); + } + } + if (pckt_count < sp->batch_size) { + // No more packets to read, it is essential for cached packet processing + *read_next_packet = false; + } + sp->pckt_count = pckt_count; + dbgx(2, + "Sending packets with LIBXDP in batch, packet numbers from " COUNTER_SPEC " to " COUNTER_SPEC "\n", + *packetnum - pckt_count + 1, + *packetnum); +} +#endif /* HAVE_LIBXDP */ diff --git a/src/send_packets.h b/src/send_packets.h index eb60be404..2c3335d70 100644 --- a/src/send_packets.h +++ b/src/send_packets.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -27,3 +27,14 @@ void send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx); void send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int idx1, pcap_t *pcap2, int idx2); void *cache_mode(tcpreplay_t *ctx, char *cachedata, COUNTER packet_num); void preload_pcap_file(tcpreplay_t *ctx, int idx); +#ifdef HAVE_LIBXDP +void prepare_remaining_elements_of_batch(tcpreplay_t *ctx, + COUNTER *packetnum, + bool *read_next_packet, + pcap_t *pcap, + int *idx, + struct pcap_pkthdr pkthdr, + packet_cache_t **prev_packet); +void prepare_first_element_of_batch(tcpreplay_t *ctx, COUNTER *packetnum, u_char *pktdata, u_int32_t len); +void fill_umem_with_data_and_set_xdp_desc(sendpacket_t *sp, int tx_idx, COUNTER umem_index, u_char *pktdata, int len); +#endif diff --git a/src/signal_handler.c b/src/signal_handler.c index 9bfd56ee6..e3eb0264e 100644 --- a/src/signal_handler.c +++ b/src/signal_handler.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/signal_handler.h b/src/signal_handler.h index db1ef91cb..a66a1ca9f 100644 --- a/src/signal_handler.h +++ b/src/signal_handler.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/sleep.c b/src/sleep.c index 05b2ef10b..d187377fd 100644 --- a/src/sleep.c +++ b/src/sleep.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -49,32 +49,32 @@ ioport_sleep_init(void) } void -ioport_sleep(sendpacket_t *sp _U_, const struct timespec *nap _U_, struct timeval *now _U_, bool flush _U_) +ioport_sleep(sendpacket_t *sp _U_, const struct timespec *nap _U_, struct timespec *now _U_, bool flush _U_) { #if defined HAVE_IOPORT_SLEEP__ - struct timeval nap_for; - u_int32_t usec; + struct timespec nap_for; + u_int32_t nsec; time_t i; - TIMESPEC_TO_TIMEVAL(&nap_for, nap); + TIMESPEC_SET(&nap_for, nap); /* * process the seconds, we do this in a loop so we don't have to * use slower 64bit integers or worry about integer overflows. */ for (i = 0; i < nap_for.tv_sec; i++) { - usec = SEC_TO_MICROSEC(nap_for.tv_sec); + nsec = nap_for.tv_sec * 1000000000; while (usec > 0) { usec--; outb(ioport_sleep_value, 0x80); } } - /* process the usec */ - usec = nap->tv_nsec / 1000; - usec--; /* fudge factor for all the above */ - while (usec > 0) { - usec--; + /* process the nsec */ + nsec = nap->tv_nsec; + nsec--; /* fudge factor for all the above */ + while (nsec > 0) { + nsec--; outb(ioport_sleep_value, 0x80); } #else diff --git a/src/sleep.h b/src/sleep.h index 0606a0e4b..5ccb9f779 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -32,6 +32,7 @@ #include #include #include +#include #include #ifdef HAVE_SYS_EVENT #include @@ -51,15 +52,22 @@ #endif /* HAVE_NETMAP */ static inline void -nanosleep_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval *now, bool flush _U_) +nanosleep_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timespec *now, bool flush _U_) { +#if defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L + struct timespec sleep_until; + timeradd_timespec(now, nap, &sleep_until); + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleep_until, NULL); +#else nanosleep(nap, NULL); +#endif + #ifdef HAVE_NETMAP if (flush) ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* flush TX buffer */ #endif /* HAVE_NETMAP */ - gettimeofday(now, NULL); + get_current_time(now); } /* @@ -69,36 +77,35 @@ nanosleep_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval * Note: make sure "now" has recently been updated. */ static inline void -gettimeofday_sleep(sendpacket_t *sp _U_, struct timespec *nap, struct timeval *now, bool flush _U_) +gettimeofday_sleep(sendpacket_t *sp, struct timespec *nap, struct timespec *now, bool flush _U_) { - struct timeval sleep_until, nap_for; + struct timespec sleep_until; #ifdef HAVE_NETMAP - struct timeval last; + struct timespec last; uint32_t i = 0; - TIMEVAL_SET(&last, now); + TIMESPEC_SET(&last, now); #endif /* HAVE_NETMAP */ - TIMESPEC_TO_TIMEVAL(&nap_for, nap); - timeradd(now, &nap_for, &sleep_until); + timeradd_timespec(now, nap, &sleep_until); while (!sp->abort) { #ifdef HAVE_NETMAP - if (flush && timercmp(now, &last, !=)) { - TIMEVAL_SET(&last, now); + if (flush && timescmp(now, &last, !=)) { + TIMESPEC_SET(&last, now); if ((++i & 0xf) == 0) /* flush TX buffer every 16 usec */ ioctl(sp->handle.fd, NIOCTXSYNC, NULL); } #endif /* HAVE_NETMAP */ - if (timercmp(now, &sleep_until, >=)) + if (timescmp(now, &sleep_until, >=)) break; #ifdef HAVE_SCHED_H /* yield the CPU so other apps remain responsive */ sched_yield(); #endif - gettimeofday(now, NULL); + get_current_time(now); } } @@ -110,15 +117,17 @@ gettimeofday_sleep(sendpacket_t *sp _U_, struct timespec *nap, struct timeval *n * for future reference */ static inline void -select_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval *now, bool flush _U_) +select_sleep(sendpacket_t *sp _U_, struct timespec *nap, struct timespec *now_ns, bool flush _U_) { struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; #ifdef HAVE_NETMAP if (flush) ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* flush TX buffer */ #endif /* HAVE_NETMAP */ - TIMESPEC_TO_TIMEVAL(&timeout, nap); + TIMEVAL_TO_TIMESPEC(&timeout, nap); if (select(0, NULL, NULL, NULL, &timeout) < 0) warnx("select_sleep() returned early due to error: %s", strerror(errno)); @@ -128,7 +137,7 @@ select_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval *n ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* flush TX buffer */ #endif - gettimeofday(now, NULL); + get_current_time(now_ns); } #endif /* HAVE_SELECT */ @@ -143,4 +152,4 @@ select_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval *n /* before calling port_sleep(), you have to call port_sleep_init() */ void ioport_sleep_init(void); -void ioport_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval *now, bool flush); +void ioport_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timespec *now, bool flush); diff --git a/src/tcpbridge.c b/src/tcpbridge.c index be7dc19db..c8acb5762 100644 --- a/src/tcpbridge.c +++ b/src/tcpbridge.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -91,9 +91,9 @@ main(int argc, char *argv[]) } #endif - if (gettimeofday(&stats.start_time, NULL) < 0) { + if (get_current_time(&stats.start_time) < 0) { tcpedit_close(&tcpedit); - err(-1, "gettimeofday() failed"); + err(-1, "get_current_time() failed"); } /* process packets */ @@ -149,7 +149,8 @@ post_args(_U_ int argc, _U_ char *argv[]) if (HAVE_OPT(DBUG)) warn("not configured with --enable-debug. Debugging disabled."); #endif - + if (HAVE_OPT(SUPPRESS_WARNINGS)) + print_warnings = 0; #ifdef ENABLE_VERBOSE if (HAVE_OPT(VERBOSE)) options.verbose = 1; diff --git a/src/tcpbridge.h b/src/tcpbridge.h index 717bf2185..7d1d7ad7e 100644 --- a/src/tcpbridge.h +++ b/src/tcpbridge.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpbridge_opts.def b/src/tcpbridge_opts.def index a1f811ea0..ee1f13f44 100644 --- a/src/tcpbridge_opts.def +++ b/src/tcpbridge_opts.def @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -23,12 +23,12 @@ autogen definitions options; copyright = { - date = "2000-2022"; + date = "2000-2024"; owner = "Aaron Turner and Fred Klassen"; eaddr = "tcpreplay-users@lists.sourceforge.net"; type = gpl; author = <<- EOText -Copyright 2013-2022 Fred Klassen - AppNeta +Copyright 2013-2024 Fred Klassen - AppNeta Copyright 2000-2012 Aaron Turner @@ -366,7 +366,7 @@ flag = { fprintf(stderr, " (debug)"); #endif fprintf(stderr, "\n"); - fprintf(stderr, "Copyright 2013-2022 by Fred Klassen - AppNeta\n"); + fprintf(stderr, "Copyright 2013-2024 by Fred Klassen - AppNeta\n"); fprintf(stderr, "Copyright 2000-2012 by Aaron Turner \n"); fprintf(stderr, "The entire Tcpreplay Suite is licensed under the GPLv3\n"); #ifdef HAVE_LIBDNET @@ -411,3 +411,13 @@ flag = { EOHelp; doc = ""; }; + +flag = { + name = suppress-warnings; + value = w; + immediate; + descrip = "suppress printing warning messages"; + settable; + doc = ""; +}; + diff --git a/src/tcpcapinfo.c b/src/tcpcapinfo.c index 4182a68ca..3985b2ae4 100644 --- a/src/tcpcapinfo.c +++ b/src/tcpcapinfo.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2012 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpcapinfo_opts.def b/src/tcpcapinfo_opts.def index 978dbb2a5..06a84511e 100644 --- a/src/tcpcapinfo_opts.def +++ b/src/tcpcapinfo_opts.def @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -102,7 +102,7 @@ flag = { fprintf(stderr, " (debug)"); #endif fprintf(stderr, "\n"); - fprintf(stderr, "Copyright 2013-2022 by Fred Klassen - AppNeta\n"); + fprintf(stderr, "Copyright 2013-2024 by Fred Klassen - AppNeta\n"); fprintf(stderr, "Copyright 2000-2010 by Aaron Turner \n"); fprintf(stderr, "The entire Tcpreplay Suite is licensed under the GPLv3\n"); exit(0); diff --git a/src/tcpedit/checksum.c b/src/tcpedit/checksum.c index 07abe5da4..52d9cb65a 100644 --- a/src/tcpedit/checksum.c +++ b/src/tcpedit/checksum.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/checksum.h b/src/tcpedit/checksum.h index aa5d13810..6eb7bf9f4 100644 --- a/src/tcpedit/checksum.h +++ b/src/tcpedit/checksum.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/dlt.c b/src/tcpedit/dlt.c index 56d64b1f3..6d457fdd7 100644 --- a/src/tcpedit/dlt.c +++ b/src/tcpedit/dlt.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -21,6 +21,7 @@ #include "dlt.h" #include "config.h" #include "tcpedit.h" +#include #include /** @@ -49,13 +50,13 @@ dlt2layer2len(tcpedit_t *tcpedit, int dlt) case DLT_EN10MB: len = 12; break; - /* - case DLT_VLAN: - len = 14; - break; - */ + case DLT_LINUX_SLL: - len = 16; + len = SLL_HDR_LEN; + break; + + case DLT_LINUX_SLL2: + len = SLL2_HDR_LEN; break; case DLT_PPP_SERIAL: @@ -103,6 +104,7 @@ dltrequires(tcpedit_t *tcpedit, int dlt) break; case DLT_LINUX_SLL: + case DLT_LINUX_SLL2: /* we have proto & SRC address */ req = TCPEDIT_DLT_DST; break; @@ -136,6 +138,7 @@ dlt2mtu(tcpedit_t *tcpedit, int dlt) break; case DLT_LINUX_SLL: + case DLT_LINUX_SLL2: mtu = 16436; break; diff --git a/src/tcpedit/dlt.h b/src/tcpedit/dlt.h index 18bc969a4..a29cd7a6b 100644 --- a/src/tcpedit/dlt.h +++ b/src/tcpedit/dlt.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/edit_packet.c b/src/tcpedit/edit_packet.c index 1025ff90d..94ac903f4 100644 --- a/src/tcpedit/edit_packet.c +++ b/src/tcpedit/edit_packet.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -78,12 +78,13 @@ fix_ipv4_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr, ipv4_hdr_t *i /* calc the L4 checksum if we have the whole packet && not a frag or first frag */ if (pkthdr->caplen == pkthdr->len && (htons(ip_hdr->ip_off) & (IP_MF | IP_OFFMASK)) == 0) { if (ip_len != (int)(pkthdr->caplen - l2len)) { - tcpedit_seterr(tcpedit, - "caplen minus L2 length %u does IPv4 header length %u: pkt=" COUNTER_SPEC, - pkthdr->caplen - l2len, - ip_len, - tcpedit->runtime.packetnum); - return TCPEDIT_ERROR; + tcpedit_setwarn(tcpedit, + "skipping packet " COUNTER_SPEC " because caplen %u minus L2 length %u does not equal IPv4 header length %u. Consider option '--fixhdrlen'.", + tcpedit->runtime.packetnum, + pkthdr->caplen, + l2len, + ip_len); + return TCPEDIT_WARN; } ret1 = do_checksum(tcpedit, (u_char *)ip_hdr, diff --git a/src/tcpedit/edit_packet.h b/src/tcpedit/edit_packet.h index d221cc8b2..a507f795c 100644 --- a/src/tcpedit/edit_packet.h +++ b/src/tcpedit/edit_packet.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/parse_args.c b/src/tcpedit/parse_args.c index 0ec4a1761..02694b9a3 100644 --- a/src/tcpedit/parse_args.c +++ b/src/tcpedit/parse_args.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -95,6 +95,10 @@ tcpedit_post_args(tcpedit_t *tcpedit) if (HAVE_OPT(FIXCSUM)) tcpedit->fixcsum = true; + /* --fixhdrlen */ + if (HAVE_OPT(FIXHDRLEN)) + tcpedit->fixhdrlen = true; + /* --efcs */ if (HAVE_OPT(EFCS)) tcpedit->efcs = true; diff --git a/src/tcpedit/parse_args.h b/src/tcpedit/parse_args.h index c6ecd81b6..639247d1d 100644 --- a/src/tcpedit/parse_args.h +++ b/src/tcpedit/parse_args.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins.h b/src/tcpedit/plugins.h index 02eedb0b2..2d3b8807f 100644 --- a/src/tcpedit/plugins.h +++ b/src/tcpedit/plugins.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/Makefile.am b/src/tcpedit/plugins/Makefile.am index c99e27413..9b6dd40c4 100644 --- a/src/tcpedit/plugins/Makefile.am +++ b/src/tcpedit/plugins/Makefile.am @@ -42,6 +42,7 @@ include %reldir%/dlt_raw/Makefile.am include %reldir%/dlt_null/Makefile.am include %reldir%/dlt_loop/Makefile.am include %reldir%/dlt_linuxsll/Makefile.am +include %reldir%/dlt_linuxsll2/Makefile.am include %reldir%/dlt_ieee80211/Makefile.am include %reldir%/dlt_radiotap/Makefile.am include %reldir%/dlt_jnpr_ether/Makefile.am diff --git a/src/tcpedit/plugins/dlt_en10mb/en10mb.c b/src/tcpedit/plugins/dlt_en10mb/en10mb.c index 0c24d8e5f..8a8b23300 100644 --- a/src/tcpedit/plugins/dlt_en10mb/en10mb.c +++ b/src/tcpedit/plugins/dlt_en10mb/en10mb.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -184,7 +184,7 @@ dlt_en10mb_parse_subsmac(tcpeditdlt_t *ctx, en10mb_config_t *config, const char { size_t input_len = strlen(input); size_t possible_entries_number = (input_len / (SUBSMAC_ENTRY_LEN + 1)) + 1; - int entry; + size_t entry; en10mb_sub_entry_t *entries = safe_malloc(possible_entries_number * sizeof(en10mb_sub_entry_t)); @@ -519,12 +519,12 @@ dlt_en10mb_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, tcpr_dir_t dir) } /* newl2len for some other DLT -> ethernet */ - else if (config->vlan == TCPEDIT_VLAN_ADD) { - /* if add a vlan then 18, */ - newl2len = TCPR_802_1Q_H; + else { + newl2len = config->vlan == TCPEDIT_VLAN_ADD ? TCPR_802_1Q_H : TCPR_802_3_H; + oldl2len = ctx->l2len; } - if (pktlen < newl2len || pktlen + newl2len - ctx->l2len > MAXPACKET) { + if ((uint32_t)pktlen < newl2len || pktlen + newl2len - ctx->l2len > MAXPACKET) { tcpedit_seterr(ctx->tcpedit, "Unable to process packet #" COUNTER_SPEC " since its new length is %d bytes.", ctx->tcpedit->runtime.packetnum, @@ -555,7 +555,6 @@ dlt_en10mb_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, tcpr_dir_t dir) /* update the total packet length */ pktlen += (int)(newl2len - oldl2len); - ctx->l2len += (int)(newl2len - oldl2len); /* set the src & dst address as the first 12 bytes */ eth = (struct tcpr_ethernet_hdr *)(packet + ctx->l2offset); @@ -665,6 +664,11 @@ dlt_en10mb_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, tcpr_dir_t dir) } } + if (newl2len == TCPR_802_3_H) { + /* all we need for 802.3 is the proto */ + eth->ether_type = ctx->proto; + } + if (config->vlan == TCPEDIT_VLAN_ADD || (config->vlan == TCPEDIT_VLAN_OFF && extra->vlan)) { vlan_hdr = (struct tcpr_802_1q_hdr *)(packet + extra->vlan_offset); if (config->vlan == TCPEDIT_VLAN_ADD) { @@ -812,7 +816,7 @@ dlt_en10mb_merge_layer3(tcpeditdlt_t *ctx, u_char *packet, int pktlen, u_char *i if (l2len == -1 || pktlen < l2len) return NULL; - assert(ctx->decoded_extra_size == sizeof(*extra)); + assert(ctx->decoded_extra_size >= sizeof(*extra)); extra = (en10mb_extra_t *)ctx->decoded_extra; eth = (struct tcpr_ethernet_hdr *)(packet + ctx->l2offset); assert(eth); diff --git a/src/tcpedit/plugins/dlt_en10mb/en10mb.h b/src/tcpedit/plugins/dlt_en10mb/en10mb.h index efc1e5500..cb5b35e33 100644 --- a/src/tcpedit/plugins/dlt_en10mb/en10mb.h +++ b/src/tcpedit/plugins/dlt_en10mb/en10mb.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_en10mb/en10mb_api.c b/src/tcpedit/plugins/dlt_en10mb/en10mb_api.c index 6fa31a863..a90b332db 100644 --- a/src/tcpedit/plugins/dlt_en10mb/en10mb_api.c +++ b/src/tcpedit/plugins/dlt_en10mb/en10mb_api.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_en10mb/en10mb_api.h b/src/tcpedit/plugins/dlt_en10mb/en10mb_api.h index 20940e23b..2b1ad3a51 100644 --- a/src/tcpedit/plugins/dlt_en10mb/en10mb_api.h +++ b/src/tcpedit/plugins/dlt_en10mb/en10mb_api.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_en10mb/en10mb_types.h b/src/tcpedit/plugins/dlt_en10mb/en10mb_types.h index 77cedacec..d1f9a275e 100644 --- a/src/tcpedit/plugins/dlt_en10mb/en10mb_types.h +++ b/src/tcpedit/plugins/dlt_en10mb/en10mb_types.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_hdlc/hdlc.c b/src/tcpedit/plugins/dlt_hdlc/hdlc.c index d2cbcda12..41c9349c3 100644 --- a/src/tcpedit/plugins/dlt_hdlc/hdlc.c +++ b/src/tcpedit/plugins/dlt_hdlc/hdlc.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_hdlc/hdlc.h b/src/tcpedit/plugins/dlt_hdlc/hdlc.h index 379d17280..f6a6fbbf3 100644 --- a/src/tcpedit/plugins/dlt_hdlc/hdlc.h +++ b/src/tcpedit/plugins/dlt_hdlc/hdlc.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_hdlc/hdlc_api.c b/src/tcpedit/plugins/dlt_hdlc/hdlc_api.c index 516dcfac4..34c8a110c 100644 --- a/src/tcpedit/plugins/dlt_hdlc/hdlc_api.c +++ b/src/tcpedit/plugins/dlt_hdlc/hdlc_api.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_hdlc/hdlc_api.h b/src/tcpedit/plugins/dlt_hdlc/hdlc_api.h index c5851cb4c..fd419f2ab 100644 --- a/src/tcpedit/plugins/dlt_hdlc/hdlc_api.h +++ b/src/tcpedit/plugins/dlt_hdlc/hdlc_api.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_hdlc/hdlc_types.h b/src/tcpedit/plugins/dlt_hdlc/hdlc_types.h index 60d2c519e..c1930455c 100644 --- a/src/tcpedit/plugins/dlt_hdlc/hdlc_types.h +++ b/src/tcpedit/plugins/dlt_hdlc/hdlc_types.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_ieee80211/ieee80211.c b/src/tcpedit/plugins/dlt_ieee80211/ieee80211.c index 092bddf9c..c82cfc751 100644 --- a/src/tcpedit/plugins/dlt_ieee80211/ieee80211.c +++ b/src/tcpedit/plugins/dlt_ieee80211/ieee80211.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_ieee80211/ieee80211.h b/src/tcpedit/plugins/dlt_ieee80211/ieee80211.h index b983914e8..d65183ae4 100644 --- a/src/tcpedit/plugins/dlt_ieee80211/ieee80211.h +++ b/src/tcpedit/plugins/dlt_ieee80211/ieee80211.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.c b/src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.c index 12b238356..8b7207310 100644 --- a/src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.c +++ b/src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.h b/src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.h index 77c6c23d1..6f846e53e 100644 --- a/src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.h +++ b/src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_ieee80211/ieee80211_types.h b/src/tcpedit/plugins/dlt_ieee80211/ieee80211_types.h index 06f02deeb..4b0b10d11 100644 --- a/src/tcpedit/plugins/dlt_ieee80211/ieee80211_types.h +++ b/src/tcpedit/plugins/dlt_ieee80211/ieee80211_types.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.c b/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.c index c53ec2973..f96e4242a 100644 --- a/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.c +++ b/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2006-2007 Aaron Turner. - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,9 +64,7 @@ dlt_jnpr_ether_register(tcpeditdlt_t *ctx) plugin = tcpedit_dlt_newplugin(); plugin->provides += PLUGIN_MASK_PROTO + PLUGIN_MASK_SRCADDR + PLUGIN_MASK_DSTADDR; - plugin-> - requires - = 0; + plugin->requires = 0; /* what is our DLT value? */ plugin->dlt = dlt_value; @@ -164,8 +162,9 @@ dlt_jnpr_ether_cleanup(tcpeditdlt_t *ctx) jnpr_ether_config_t *config; config = (jnpr_ether_config_t *)ctx->encoder->config; - if (config->subctx != NULL) + if (config != NULL && config->subctx != NULL) { tcpedit_dlt_cleanup(config->subctx); + } safe_free(plugin->config); plugin->config = NULL; plugin->config_size = 0; @@ -303,6 +302,13 @@ dlt_jnpr_ether_proto(tcpeditdlt_t *ctx, const u_char *packet, int pktlen) memcpy(&jnpr_hdr_len, &packet[JUNIPER_ETHER_EXTLEN_OFFSET], 2); jnpr_hdr_len = ntohs(jnpr_hdr_len) + JUNIPER_ETHER_HEADER_LEN; + if (jnpr_hdr_len > pktlen) { + tcpedit_seterr(ctx->tcpedit, + "Juniper header length %d invalid: it is greater than packet length %d", + jnpr_hdr_len, pktlen); + return TCPEDIT_ERROR; + } + ethernet = packet + jnpr_hdr_len; /* let the en10mb plugin do the rest of the work */ diff --git a/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.h b/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.h index 4875350d2..11bd372fa 100644 --- a/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.h +++ b/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_api.c b/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_api.c index 393c4d254..b8693a12e 100644 --- a/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_api.c +++ b/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_api.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2009 Aaron Turner. - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_api.h b/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_api.h index dbfaea8bb..3bb60a2c2 100644 --- a/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_api.h +++ b/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_api.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_types.h b/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_types.h index 95b466f7e..5f1013ccf 100644 --- a/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_types.h +++ b/src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether_types.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_linuxsll/linuxsll.c b/src/tcpedit/plugins/dlt_linuxsll/linuxsll.c index e6dfeb2f7..ee4f2793b 100644 --- a/src/tcpedit/plugins/dlt_linuxsll/linuxsll.c +++ b/src/tcpedit/plugins/dlt_linuxsll/linuxsll.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_linuxsll/linuxsll.h b/src/tcpedit/plugins/dlt_linuxsll/linuxsll.h index eb2b26e34..113a4e3ee 100644 --- a/src/tcpedit/plugins/dlt_linuxsll/linuxsll.h +++ b/src/tcpedit/plugins/dlt_linuxsll/linuxsll.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_linuxsll2/Makefile.am b/src/tcpedit/plugins/dlt_linuxsll2/Makefile.am new file mode 100644 index 000000000..6ec1fbbcb --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/Makefile.am @@ -0,0 +1,30 @@ +# $Id:$ +# START OF: dlt_linuxsll2 +# Note, if you add any files to your plugin, you will need to edit dlt_/Makefile.am +# add your .c files to libtcpedit_a_SOURCES +# add your .h files to noinst_HEADERS +# add any other files (like documentation, notes, etc) to EXTRA_DIST +# add your dependency information (see comment below) + +libtcpedit_a_SOURCES += %reldir%/linuxsll2.c + +noinst_HEADERS += \ + %reldir%/linuxsll2.h \ + %reldir%/linuxsll2_types.h + +EXTRA_DIST += %reldir%/linuxsll2_opts.def + +# dependencies for your plugin source code. Edit as necessary +linuxsll2.c: \ + $(TCPEDIT_PLUGINS_DEPS) \ + %reldir%/../../tcpedit_api.h \ + %reldir%/linuxsll2.h \ + %reldir%/linuxsll2_types.h + +# You probably don't want to touch anything below this line until the end of the plugin + +DLT_STUB_DEPS += %reldir%/linuxsll2_opts.def + +MOSTLYCLEANFILES += *~ + +# END OF: dlt_linuxsll2 diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c new file mode 100644 index 000000000..2c5812166 --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c @@ -0,0 +1,326 @@ +/* $Id$ */ + +/* + * Copyright (c) 2001-2010 Aaron Turner + * Copyright (c) 2013-2023 Fred Klassen - AppNeta + * + * The Tcpreplay Suite of tools is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or with the authors permission any later version. + * + * The Tcpreplay Suite is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Tcpreplay Suite. If not, see . + */ + +#include +#include + +#include "tcpedit.h" +#include "common.h" +#include "tcpr.h" +#include "dlt_utils.h" +#include "tcpedit_stub.h" +#include "../ethernet.h" +#include "linuxsll2.h" + + +static char dlt_name[] = "linuxsll2"; +static char _U_ dlt_prefix[] = "linuxsll2"; +static uint16_t dlt_value = DLT_LINUX_SLL2; + +/* + * Function to register ourselves. This function is always called, regardless + * of what DLT types are being used, so it shouldn't be allocating extra buffers + * or anything like that (use the dlt_linuxsll2_init() function below for that). + * Tasks: + * - Create a new plugin struct + * - Fill out the provides/requires bit masks. Note: Only specify which fields are + * actually in the header. + * - Add the plugin to the context's plugin chain + * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN + */ +int +dlt_linuxsll2_register(tcpeditdlt_t *ctx) +{ + tcpeditdlt_plugin_t *plugin; + assert(ctx); + + /* create a new plugin structure */ + plugin = tcpedit_dlt_newplugin(); + + /* FIXME: set what we provide & require */ + plugin->provides += PLUGIN_MASK_PROTO + PLUGIN_MASK_SRCADDR; + plugin->requires += 0; + + + /* what is our DLT value? */ + plugin->dlt = dlt_value; + + /* set the prefix name of our plugin. This is also used as the prefix for our options */ + plugin->name = safe_strdup(dlt_prefix); + + /* + * Point to our functions, note, you need a function for EVERY method. + * Even if it is only an empty stub returning success. + */ + plugin->plugin_init = dlt_linuxsll2_init; + plugin->plugin_cleanup = dlt_linuxsll2_cleanup; + plugin->plugin_parse_opts = dlt_linuxsll2_parse_opts; + plugin->plugin_decode = dlt_linuxsll2_decode; + plugin->plugin_encode = dlt_linuxsll2_encode; + plugin->plugin_proto = dlt_linuxsll2_proto; + plugin->plugin_l2addr_type = dlt_linuxsll2_l2addr_type; + plugin->plugin_l2len = dlt_linuxsll2_l2len; + plugin->plugin_get_layer3 = dlt_linuxsll2_get_layer3; + plugin->plugin_merge_layer3 = dlt_linuxsll2_merge_layer3; + plugin->plugin_get_mac = dlt_linuxsll2_get_mac; + + /* add it to the available plugin list */ + return tcpedit_dlt_addplugin(ctx, plugin); +} + +/* + * Initializer function. This function is called only once, if and only if + * this plugin will be utilized. Remember, if you need to keep track of any state, + * store it in your plugin->config, not a global! + * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN + */ +int +dlt_linuxsll2_init(tcpeditdlt_t *ctx) +{ + tcpeditdlt_plugin_t *plugin; + assert(ctx); + + if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) { + tcpedit_seterr(ctx->tcpedit, "Unable to initialize unregistered plugin %s", dlt_name); + return TCPEDIT_ERROR; + } + + /* allocate memory for our decode extra data */ + if (ctx->decoded_extra_size > 0) { + if (ctx->decoded_extra_size < sizeof(linuxsll2_extra_t)) { + ctx->decoded_extra_size = sizeof(linuxsll2_extra_t); + ctx->decoded_extra = safe_realloc(ctx->decoded_extra, ctx->decoded_extra_size); + } + } else { + ctx->decoded_extra_size = sizeof(linuxsll2_extra_t); + ctx->decoded_extra = safe_malloc(ctx->decoded_extra_size); + } + + /* allocate memory for our config data */ + plugin->config_size = sizeof(linuxsll2_config_t); + plugin->config = safe_malloc(plugin->config_size); + + return TCPEDIT_OK; /* success */ +} + +/* + * Since this is used in a library, we should manually clean up after ourselves + * Unless you allocated some memory in dlt_linuxsll2_init(), this is just an stub. + * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN + */ +int +dlt_linuxsll2_cleanup(tcpeditdlt_t *ctx) +{ + tcpeditdlt_plugin_t *plugin; + assert(ctx); + + if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) { + tcpedit_seterr(ctx->tcpedit, "Unable to cleanup unregistered plugin %s", dlt_name); + return TCPEDIT_ERROR; + } + + if (ctx->decoded_extra != NULL) { + safe_free(ctx->decoded_extra); + ctx->decoded_extra = NULL; + ctx->decoded_extra_size = 0; + } + + safe_free(plugin->name); + plugin->name = NULL; + if (plugin->config != NULL) { + safe_free(plugin->config); + plugin->config = NULL; + plugin->config_size = 0; + } + + return TCPEDIT_OK; /* success */ +} + +/* + * This is where you should define all your AutoGen AutoOpts option parsing. + * Any user specified option should have it's bit turned on in the 'provides' + * bit mask. + * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN + */ +int +dlt_linuxsll2_parse_opts(tcpeditdlt_t *ctx) +{ + assert(ctx); + + /* nothing to parse */ + return TCPEDIT_OK; /* success */ +} + +/* + * Function to decode the layer 2 header in the packet. + * You need to fill out: + * - ctx->l2len + * - ctx->srcaddr + * - ctx->dstaddr + * - ctx->proto + * - ctx->decoded_extra + * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN + */ +int +dlt_linuxsll2_decode(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) +{ + int type; + linux_sll2_header_t *linux_sll2; + assert(ctx); + assert(packet); + + if (pktlen < (int)sizeof(linux_sll2_header_t)) + return TCPEDIT_ERROR; + + linux_sll2 = (linux_sll2_header_t *)packet; + ctx->proto = linux_sll2->proto; + ctx->l2len = sizeof(linux_sll2_header_t); + + + type = ntohs(linux_sll2->type); + if (type == ARPHRD_ETHER || type == ARPHRD_LOOPBACK) { /* ethernet or loopback */ + memcpy(&(ctx->srcaddr), linux_sll2->address, ETHER_ADDR_LEN); + } else { + tcpedit_seterr(ctx->tcpedit, "%s", "DLT_LINUX_SLL2 pcap's must contain only ethernet or loopback packets"); + return TCPEDIT_ERROR; + } + + return TCPEDIT_OK; /* success */ +} + +/* + * Function to encode the layer 2 header back into the packet. + * Returns: total packet len or TCPEDIT_ERROR + */ +int +dlt_linuxsll2_encode(tcpeditdlt_t *ctx, u_char *packet, _U_ int pktlen, + _U_ tcpr_dir_t dir) +{ + assert(ctx); + assert(packet); + + tcpedit_seterr(ctx->tcpedit, "%s", "DLT_LINUX_SLL2 plugin does not support packet encoding"); + return TCPEDIT_ERROR; +} + +/* + * Function returns the Layer 3 protocol type of the given packet, or TCPEDIT_ERROR on error + */ +int +dlt_linuxsll2_proto(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) +{ + linux_sll2_header_t *linux_sll2; + assert(ctx); + assert(packet); + + if (pktlen < (int)sizeof(linux_sll2_header_t)) + return TCPEDIT_ERROR; + + linux_sll2 = (linux_sll2_header_t *)packet; + + return linux_sll2->proto; +} + +/* + * Function returns a pointer to the layer 3 protocol header or NULL on error + */ +u_char * +dlt_linuxsll2_get_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen) +{ + int l2len; + assert(ctx); + assert(packet); + + l2len = dlt_linuxsll2_l2len(ctx, packet, pktlen); + if (l2len == -1 || pktlen < l2len) + return NULL; + + return tcpedit_dlt_l3data_copy(ctx, packet, pktlen, l2len); +} + +/* + * function merges the packet (containing L2 and old L3) with the l3data buffer + * containing the new l3 data. Note, if L2 % 4 == 0, then they're pointing to the + * same buffer, otherwise there was a memcpy involved on strictly aligned architectures + * like SPARC + */ +u_char * +dlt_linuxsll2_merge_layer3(tcpeditdlt_t *ctx, u_char *packet, int pktlen, u_char *ipv4_data, u_char *ipv6_data) +{ + int l2len; + assert(ctx); + assert(packet); + assert(ipv4_data || ipv6_data); + + l2len = dlt_linuxsll2_l2len(ctx, packet, pktlen); + if (l2len == -1 || pktlen < l2len) + return NULL; + + return tcpedit_dlt_l3data_merge(ctx, packet, pktlen, ipv4_data ?: ipv6_data, l2len); +} + +/* + * return the length of the L2 header of the current packet + */ +int +dlt_linuxsll2_l2len(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) +{ + assert(ctx); + assert(packet); + + if (pktlen < (int)sizeof(linux_sll2_header_t)) + return -1; + + return sizeof(linux_sll2_header_t); +} + +/* + * return a static pointer to the source/destination MAC address + * return NULL on error/address doesn't exist + */ +u_char * +dlt_linuxsll2_get_mac(tcpeditdlt_t *ctx, tcpeditdlt_mac_type_t mac, const u_char *packet, const int pktlen) +{ + assert(ctx); + assert(packet); + + if (pktlen < 14) + return NULL; + + /* FIXME: return a ptr to the source or dest mac address. */ + switch(mac) { + case SRC_MAC: + memcpy(ctx->srcmac, &packet[6], 8); /* linuxssl defines the src mac field to be 8 bytes, not 6 */ + return ctx->srcmac; + case DST_MAC: + break; + default: + errx(-1, "Invalid tcpeditdlt_mac_type_t: %d", mac); + } + return NULL; +} + +tcpeditdlt_l2addr_type_t +dlt_linuxsll2_l2addr_type(void) +{ + /* we only support ethernet packets */ + return ETHERNET; +} + diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h new file mode 100644 index 000000000..0a76988bd --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h @@ -0,0 +1,54 @@ +/* $Id$ */ + +/* + * Copyright (c) 2001-2010 Aaron Turner + * Copyright (c) 2013-2023 Fred Klassen - AppNeta + * + * The Tcpreplay Suite of tools is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or with the authors permission any later version. + * + * The Tcpreplay Suite is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Tcpreplay Suite. If not, see . + */ + +#ifndef _DLT_linuxsll2_H_ +#define _DLT_linuxsll2_H_ + +#include "plugins_types.h" +#include "linuxsll2_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +int dlt_linuxsll2_register(tcpeditdlt_t *ctx); +int dlt_linuxsll2_init(tcpeditdlt_t *ctx); +int dlt_linuxsll2_cleanup(tcpeditdlt_t *ctx); +int dlt_linuxsll2_parse_opts(tcpeditdlt_t *ctx); +int dlt_linuxsll2_decode(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen); +int dlt_linuxsll2_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, tcpr_dir_t dir); +int dlt_linuxsll2_proto(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen); +u_char *dlt_linuxsll2_get_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen); +u_char *dlt_linuxsll2_merge_layer3(tcpeditdlt_t *ctx, + u_char *packet, + int pktlen, + u_char *ipv4_data, + u_char *ipv6_data); +tcpeditdlt_l2addr_type_t dlt_linuxsll2_l2addr_type(void); +int dlt_linuxsll2_l2len(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen); +u_char *dlt_linuxsll2_get_mac(tcpeditdlt_t *ctx, tcpeditdlt_mac_type_t mac, const u_char *packet, const int pktlen); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_opts.def b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_opts.def new file mode 100644 index 000000000..07c11b5fd --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_opts.def @@ -0,0 +1 @@ +/* no options for DLT_LINUX_SLL2 */ diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_types.h b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_types.h new file mode 100644 index 000000000..d44a2cbb9 --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_types.h @@ -0,0 +1,72 @@ +/* $Id$ */ + +/* + * Copyright (c) 2001-2010 Aaron Turner + * Copyright (c) 2013-2023 Fred Klassen - AppNeta + * + * The Tcpreplay Suite of tools is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or with the authors permission any later version. + * + * The Tcpreplay Suite is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Tcpreplay Suite. If not, see . + */ + +#ifndef _DLT_linuxsll2_TYPES_H_ +#define _DLT_linuxsll2_TYPES_H_ + +#include "tcpedit_types.h" +#include "plugins_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * structure to hold any data parsed from the packet by the decoder. + * Example: Ethernet VLAN tag info + */ +typedef struct { + u_char packet[MAXPACKET]; +} linuxsll2_extra_t; + + +/* + * FIXME: structure to hold any data in the tcpeditdlt_plugin_t->config + * Things like: + * - Parsed user options + * - State between packets + * - Note, you should only use this for the encoder function, decoder functions should place + * "extra" data parsed from the packet in the tcpeditdlt_t->decoded_extra buffer since that + * is available to any encoder plugin. + */ +typedef struct { + /* dummy entry for SunPro compiler which doesn't like empty structs */ + int dummy; +} linuxsll2_config_t; + + +typedef struct { + u_int16_t proto; /* Ethernet protocol type */ + u_int16_t mbz; /* reserved */ + u_int32_t if_index; /* iface index */ + u_int16_t type; /* linux ARPHRD_* values for link-layer device type. See: + * http://www.gelato.unsw.edu.au/lxr/source/include/linux/if_arp.h + */ + u_int8_t source; /* values 0-4 determine where the packet came and where it's going */ + u_int8_t length; /* source address length */ + u_char address[8]; /* first 8 bytes of source address (may be truncated) */ +} linux_sll2_header_t; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/tcpedit/plugins/dlt_loop/loop.c b/src/tcpedit/plugins/dlt_loop/loop.c index 70b5fba02..144c04227 100644 --- a/src/tcpedit/plugins/dlt_loop/loop.c +++ b/src/tcpedit/plugins/dlt_loop/loop.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_loop/loop.h b/src/tcpedit/plugins/dlt_loop/loop.h index 5ffdcc9cb..672067ca9 100644 --- a/src/tcpedit/plugins/dlt_loop/loop.h +++ b/src/tcpedit/plugins/dlt_loop/loop.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_null/null.c b/src/tcpedit/plugins/dlt_null/null.c index cc682aa1d..e00b07c1f 100644 --- a/src/tcpedit/plugins/dlt_null/null.c +++ b/src/tcpedit/plugins/dlt_null/null.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_null/null.h b/src/tcpedit/plugins/dlt_null/null.h index fe348c515..ac231abd5 100644 --- a/src/tcpedit/plugins/dlt_null/null.h +++ b/src/tcpedit/plugins/dlt_null/null.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_plugins.c b/src/tcpedit/plugins/dlt_plugins.c index 515853789..902ed52e1 100644 --- a/src/tcpedit/plugins/dlt_plugins.c +++ b/src/tcpedit/plugins/dlt_plugins.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -33,6 +33,7 @@ #include "dlt_ieee80211/ieee80211.h" #include "dlt_jnpr_ether/jnpr_ether.h" #include "dlt_linuxsll/linuxsll.h" +#include "dlt_linuxsll2/linuxsll2.h" #include "dlt_loop/loop.h" #include "dlt_null/null.h" #include "dlt_pppserial/pppserial.h" @@ -57,6 +58,7 @@ tcpedit_dlt_register(tcpeditdlt_t *ctx) retcode += dlt_null_register(ctx); retcode += dlt_loop_register(ctx); retcode += dlt_linuxsll_register(ctx); + retcode += dlt_linuxsll2_register(ctx); retcode += dlt_ieee80211_register(ctx); retcode += dlt_radiotap_register(ctx); retcode += dlt_jnpr_ether_register(ctx); diff --git a/src/tcpedit/plugins/dlt_pppserial/pppserial.c b/src/tcpedit/plugins/dlt_pppserial/pppserial.c index 1ac135621..41404ff6b 100644 --- a/src/tcpedit/plugins/dlt_pppserial/pppserial.c +++ b/src/tcpedit/plugins/dlt_pppserial/pppserial.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2006-2007 Aaron Turner. - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/tcpedit/plugins/dlt_pppserial/pppserial.h b/src/tcpedit/plugins/dlt_pppserial/pppserial.h index 7bea1bed9..7f72754a1 100644 --- a/src/tcpedit/plugins/dlt_pppserial/pppserial.h +++ b/src/tcpedit/plugins/dlt_pppserial/pppserial.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_pppserial/pppserial_api.c b/src/tcpedit/plugins/dlt_pppserial/pppserial_api.c index a0921074a..3d9ea0cfc 100644 --- a/src/tcpedit/plugins/dlt_pppserial/pppserial_api.c +++ b/src/tcpedit/plugins/dlt_pppserial/pppserial_api.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2009 Aaron Turner. - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/tcpedit/plugins/dlt_pppserial/pppserial_api.h b/src/tcpedit/plugins/dlt_pppserial/pppserial_api.h index f37c48003..4185b0926 100644 --- a/src/tcpedit/plugins/dlt_pppserial/pppserial_api.h +++ b/src/tcpedit/plugins/dlt_pppserial/pppserial_api.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_pppserial/pppserial_types.h b/src/tcpedit/plugins/dlt_pppserial/pppserial_types.h index 3b7b33e4a..e72e143ad 100644 --- a/src/tcpedit/plugins/dlt_pppserial/pppserial_types.h +++ b/src/tcpedit/plugins/dlt_pppserial/pppserial_types.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_radiotap/radiotap.c b/src/tcpedit/plugins/dlt_radiotap/radiotap.c index 9e8754487..a02f1ba45 100644 --- a/src/tcpedit/plugins/dlt_radiotap/radiotap.c +++ b/src/tcpedit/plugins/dlt_radiotap/radiotap.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_radiotap/radiotap.h b/src/tcpedit/plugins/dlt_radiotap/radiotap.h index dfd061e98..e51f7207c 100644 --- a/src/tcpedit/plugins/dlt_radiotap/radiotap.h +++ b/src/tcpedit/plugins/dlt_radiotap/radiotap.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_raw/raw.c b/src/tcpedit/plugins/dlt_raw/raw.c index cc801b1a2..dcd2f3623 100644 --- a/src/tcpedit/plugins/dlt_raw/raw.c +++ b/src/tcpedit/plugins/dlt_raw/raw.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_raw/raw.h b/src/tcpedit/plugins/dlt_raw/raw.h index 0a7e45d32..6ebde966c 100644 --- a/src/tcpedit/plugins/dlt_raw/raw.h +++ b/src/tcpedit/plugins/dlt_raw/raw.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_stub.def b/src/tcpedit/plugins/dlt_stub.def index 1c9488980..10af36f09 100644 --- a/src/tcpedit/plugins/dlt_stub.def +++ b/src/tcpedit/plugins/dlt_stub.def @@ -8,6 +8,7 @@ #include dlt_null/null_opts.def #include dlt_loop/loop_opts.def #include dlt_linuxsll/linuxsll_opts.def +#include dlt_linuxsll2/linuxsll2_opts.def #include dlt_ieee80211/ieee80211_opts.def #include dlt_radiotap/radiotap_opts.def #include dlt_jnpr_ether/jnpr_ether_opts.def diff --git a/src/tcpedit/plugins/dlt_template/plugin.h b/src/tcpedit/plugins/dlt_template/plugin.h index 1e69bce7a..f715c8f6b 100644 --- a/src/tcpedit/plugins/dlt_template/plugin.h +++ b/src/tcpedit/plugins/dlt_template/plugin.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_template/plugin_api.h b/src/tcpedit/plugins/dlt_template/plugin_api.h index bf6d47101..07683636f 100644 --- a/src/tcpedit/plugins/dlt_template/plugin_api.h +++ b/src/tcpedit/plugins/dlt_template/plugin_api.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_template/plugin_types.h b/src/tcpedit/plugins/dlt_template/plugin_types.h index e0a6615fc..276b8b07e 100644 --- a/src/tcpedit/plugins/dlt_template/plugin_types.h +++ b/src/tcpedit/plugins/dlt_template/plugin_types.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_user/user.c b/src/tcpedit/plugins/dlt_user/user.c index b086670f5..8f90994a2 100644 --- a/src/tcpedit/plugins/dlt_user/user.c +++ b/src/tcpedit/plugins/dlt_user/user.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_user/user.h b/src/tcpedit/plugins/dlt_user/user.h index 94b5d18ac..5515a10a5 100644 --- a/src/tcpedit/plugins/dlt_user/user.h +++ b/src/tcpedit/plugins/dlt_user/user.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_user/user_api.c b/src/tcpedit/plugins/dlt_user/user_api.c index eea2544f8..8eb1131c2 100644 --- a/src/tcpedit/plugins/dlt_user/user_api.c +++ b/src/tcpedit/plugins/dlt_user/user_api.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_user/user_api.h b/src/tcpedit/plugins/dlt_user/user_api.h index f8df9d382..c686f13d4 100644 --- a/src/tcpedit/plugins/dlt_user/user_api.h +++ b/src/tcpedit/plugins/dlt_user/user_api.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_utils.c b/src/tcpedit/plugins/dlt_utils.c index 29ebf1e05..67e137658 100644 --- a/src/tcpedit/plugins/dlt_utils.c +++ b/src/tcpedit/plugins/dlt_utils.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/dlt_utils.h b/src/tcpedit/plugins/dlt_utils.h index dcc88c480..277321062 100644 --- a/src/tcpedit/plugins/dlt_utils.h +++ b/src/tcpedit/plugins/dlt_utils.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/ethernet.c b/src/tcpedit/plugins/ethernet.c index bf85a2c8f..347bb1748 100644 --- a/src/tcpedit/plugins/ethernet.c +++ b/src/tcpedit/plugins/ethernet.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins/ethernet.h b/src/tcpedit/plugins/ethernet.h index db38cc2ea..e40615057 100644 --- a/src/tcpedit/plugins/ethernet.h +++ b/src/tcpedit/plugins/ethernet.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins_api.h b/src/tcpedit/plugins_api.h index f22c07d9f..dcd05c453 100644 --- a/src/tcpedit/plugins_api.h +++ b/src/tcpedit/plugins_api.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/plugins_types.h b/src/tcpedit/plugins_types.h index fae43f2cb..d37586177 100644 --- a/src/tcpedit/plugins_types.h +++ b/src/tcpedit/plugins_types.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/portmap.c b/src/tcpedit/portmap.c index 5fe1779f9..2e3d6af4d 100644 --- a/src/tcpedit/portmap.c +++ b/src/tcpedit/portmap.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/portmap.h b/src/tcpedit/portmap.h index 05f90d523..8f9022e35 100644 --- a/src/tcpedit/portmap.h +++ b/src/tcpedit/portmap.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/tcpedit.c b/src/tcpedit/tcpedit.c index 23562b8c7..51b78bf1b 100644 --- a/src/tcpedit/tcpedit.c +++ b/src/tcpedit/tcpedit.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -94,7 +94,7 @@ tcpedit_packet(tcpedit_t *tcpedit, struct pcap_pkthdr **pkthdr, u_char **pktdata ipflags = 0; /* not everything has a L3 header, so check for errors. returns proto in network byte order */ if ((l2proto = tcpedit_dlt_proto(tcpedit->dlt_ctx, src_dlt, packet, (int)(*pkthdr)->caplen)) < 0) { - dbgx(2, "Packet has no L3+ header: %s", tcpedit_geterr(tcpedit)); + dbgx(2, "Packet " COUNTER_SPEC " has no L3+ header: %s", tcpedit->runtime.packetnum, tcpedit_geterr(tcpedit)); return TCPEDIT_SOFT_ERROR; } else { dbgx(2, "Layer 3 protocol type is: 0x%04x", ntohs(l2proto)); @@ -185,8 +185,9 @@ tcpedit_packet(tcpedit_t *tcpedit, struct pcap_pkthdr **pkthdr, u_char **pktdata volatile uint16_t oldval = *((uint16_t *)ip_hdr); volatile uint16_t newval; - ip_hdr->ip_tos = tcpedit->tos; newval = *((uint16_t *)ip_hdr); + newval = htons((ntohs(newval) & 0xff00) | (tcpedit->tos & 0xff)); + *((uint16_t *)ip_hdr) = newval; csum_replace2(&ip_hdr->ip_sum, oldval, newval); } @@ -315,12 +316,20 @@ tcpedit_packet(tcpedit_t *tcpedit, struct pcap_pkthdr **pkthdr, u_char **pktdata } } - /* ensure IP header length is correct */ - if (ip_hdr != NULL) { - fix_ipv4_length(*pkthdr, ip_hdr, l2len); - needtorecalc = 1; - } else if (ip6_hdr != NULL) { - needtorecalc |= fix_ipv6_length(*pkthdr, ip6_hdr, l2len); + /* fixhdrlen option ensure IP header length is correct */ + /* do we need to fix checksums? -- must always do this last! */ + if (tcpedit->fixhdrlen) { + /* ensure IP header length is correct */ + int changed = 0; + if (ip_hdr != NULL) { + changed = fix_ipv4_length(*pkthdr, ip_hdr, l2len); + } else if (ip6_hdr != NULL) { + changed = fix_ipv6_length(*pkthdr, ip6_hdr, l2len); + } + /* did the packet change? then needtorecalc checksum */ + if (changed > 0) { + needtorecalc |= changed; + } } /* do we need to fix checksums? -- must always do this last! */ diff --git a/src/tcpedit/tcpedit.h b/src/tcpedit/tcpedit.h index af6b18214..a7c44a398 100644 --- a/src/tcpedit/tcpedit.h +++ b/src/tcpedit/tcpedit.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/tcpedit_api.c b/src/tcpedit/tcpedit_api.c index 61d988fb8..6c7e0827a 100644 --- a/src/tcpedit/tcpedit_api.c +++ b/src/tcpedit/tcpedit_api.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -136,6 +136,17 @@ tcpedit_set_fixcsum(tcpedit_t *tcpedit, bool value) return TCPEDIT_OK; } +/** + * \brief should we fix(?) header length? + */ +int +tcpedit_set_fixhdrlen(tcpedit_t *tcpedit, bool value) +{ + assert(tcpedit); + tcpedit->fixhdrlen = value; + return TCPEDIT_OK; +} + /** * \brief should we remove the EFCS from the frame? */ diff --git a/src/tcpedit/tcpedit_api.h b/src/tcpedit/tcpedit_api.h index 50e931232..4233a9389 100644 --- a/src/tcpedit/tcpedit_api.h +++ b/src/tcpedit/tcpedit_api.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -40,6 +40,7 @@ int tcpedit_set_encoder_dltplugin_byname(tcpedit_t *, const char *); int tcpedit_set_skip_broadcast(tcpedit_t *, bool); int tcpedit_set_fixlen(tcpedit_t *, tcpedit_fixlen); int tcpedit_set_fixcsum(tcpedit_t *, bool); +int tcpedit_set_fixhdrlen(tcpedit_t *, bool); int tcpedit_set_efcs(tcpedit_t *, bool); int tcpedit_set_ttl_mode(tcpedit_t *, tcpedit_ttl_mode); int tcpedit_set_ttl_value(tcpedit_t *, uint8_t); diff --git a/src/tcpedit/tcpedit_opts.def b/src/tcpedit/tcpedit_opts.def index 3f8ee2878..5114bc3a1 100644 --- a/src/tcpedit/tcpedit_opts.def +++ b/src/tcpedit/tcpedit_opts.def @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -170,6 +170,18 @@ fixed. Automatically enabled for packets modified with @samp{--seed}, EOText; }; +flag = { + name = fixhdrlen; + descrip = "Alter IP/TCP header len to match packet length"; + doc = <<- EOText +By default, tcpreplay will send packets with the original packet length, +However, you may want the packet length revised to minimum packet size. +Using this option, tcpreplay will rewrite (fix) the packet length, +and recalculate checksums when packet length changes. +Caution: undesired packet changes may occur when this option is specified. +EOText; +}; + flag = { name = mtu; value = m; diff --git a/src/tcpedit/tcpedit_stub.def b/src/tcpedit/tcpedit_stub.def index 7b2000e97..999e834f0 100644 --- a/src/tcpedit/tcpedit_stub.def +++ b/src/tcpedit/tcpedit_stub.def @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpedit/tcpedit_types.h b/src/tcpedit/tcpedit_types.h index a0ef961b3..68a3d5df0 100644 --- a/src/tcpedit/tcpedit_types.h +++ b/src/tcpedit/tcpedit_types.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -147,6 +147,9 @@ typedef struct { uint32_t fuzz_seed; uint32_t fuzz_factor; + + /* fix header length */ + bool fixhdrlen; } tcpedit_t; #ifdef __cplusplus diff --git a/src/tcpprep.c b/src/tcpprep.c index d17014c0b..28cc2cac2 100644 --- a/src/tcpprep.c +++ b/src/tcpprep.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -91,7 +91,7 @@ main(int argc, char *argv[]) readpcap: /* open the pcap file */ - if ((options->pcap = pcap_open_offline(OPT_ARG(PCAP), errbuf)) == NULL) { + if ((options->pcap = tcpr_pcap_open(OPT_ARG(PCAP), errbuf)) == NULL) { close(out_file); tcpprep_close(tcpprep); errx(-1, "Error opening libpcap: %s", errbuf); @@ -108,6 +108,7 @@ main(int argc, char *argv[]) switch (pcap_datalink(options->pcap)) { case DLT_EN10MB: case DLT_LINUX_SLL: + case DLT_LINUX_SLL2: case DLT_RAW: case DLT_C_HDLC: case DLT_JUNIPER_ETHER: @@ -124,6 +125,9 @@ main(int argc, char *argv[]) err(-1, "MAC mode splitting is only supported by DLT_EN10MB packet captures."); } + if (HAVE_OPT(SUPPRESS_WARNINGS)) + print_warnings = 0; + #ifdef ENABLE_VERBOSE if (HAVE_OPT(VERBOSE)) { tcpdump_open(&tcpprep->tcpdump, options->pcap); diff --git a/src/tcpprep.h b/src/tcpprep.h index 0a8c4f357..c18a232be 100644 --- a/src/tcpprep.h +++ b/src/tcpprep.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpprep_api.c b/src/tcpprep_api.c index 2a9709ebd..2c68e0b0f 100644 --- a/src/tcpprep_api.c +++ b/src/tcpprep_api.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -91,6 +91,14 @@ tcpprep_close(tcpprep_t *ctx) cidr = cidr_nxt; } + if (options->xX.list) + free_list(options->xX.list); + + if (options->xX.cidr) + safe_free(options->xX.cidr); + + regfree(&options->preg); + safe_free(options); safe_free(ctx->outfile); @@ -133,6 +141,9 @@ tcpprep_post_args(tcpprep_t *ctx, int argc, char *argv[]) debug = OPT_VALUE_DBUG; #endif + if (HAVE_OPT(SUPPRESS_WARNINGS)) + print_warnings = 0; + #ifdef ENABLE_VERBOSE if (HAVE_OPT(VERBOSE)) { ctx->options->verbose = 1; diff --git a/src/tcpprep_api.h b/src/tcpprep_api.h index 279de7493..92e1da78f 100644 --- a/src/tcpprep_api.h +++ b/src/tcpprep_api.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpprep_opts.def b/src/tcpprep_opts.def index 14c0a37c3..be2ef991d 100644 --- a/src/tcpprep_opts.def +++ b/src/tcpprep_opts.def @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -21,12 +21,12 @@ autogen definitions options; copyright = { - date = "2000-2022"; + date = "2000-2024"; owner = "Aaron Turner and Fred Klassen"; eaddr = "tcpreplay-users@lists.sourceforge.net"; type = gpl; author = <<- EOText -Copyright 2013-2022 Fred Klassen - AppNeta +Copyright 2013-2024 Fred Klassen - AppNeta Copyright 2000-2012 Aaron Turner @@ -601,7 +601,7 @@ flag = { fprintf(stderr, " (debug)"); #endif fprintf(stderr, "\n"); - fprintf(stderr, "Copyright 2013-2022 by Fred Klassen - AppNeta\n"); + fprintf(stderr, "Copyright 2013-2024 by Fred Klassen - AppNeta\n"); fprintf(stderr, "Copyright 2000-2012 by Aaron Turner \n"); fprintf(stderr, "The entire Tcpreplay Suite is licensed under the GPLv3\n"); fprintf(stderr, "Cache file supported: %s\n", CACHEVERSION); @@ -644,3 +644,12 @@ flag = { EOHelp; }; + +flag = { + name = suppress-warnings; + value = w; + immediate; + descrip = "suppress printing warning messages"; + settable; + doc = ""; +}; diff --git a/src/tcpr.h b/src/tcpr.h index f258a74f2..b15382a4d 100644 --- a/src/tcpr.h +++ b/src/tcpr.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpreplay.c b/src/tcpreplay.c index 8e1b84c38..c33899a8a 100644 --- a/src/tcpreplay.c +++ b/src/tcpreplay.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -216,7 +216,7 @@ main(int argc, char *argv[]) */ static void flow_stats(const tcpreplay_t *tcpr_ctx) { - struct timeval diff; + struct timespec diff; COUNTER diff_us; const tcpreplay_stats_t *stats = &tcpr_ctx->stats; const tcpreplay_opt_t *options = tcpr_ctx->options; @@ -228,8 +228,8 @@ static void flow_stats(const tcpreplay_t *tcpr_ctx) COUNTER flows_sec = 0; u_int32_t flows_sec_100ths = 0; - timersub(&stats->end_time, &stats->start_time, &diff); - diff_us = TIMEVAL_TO_MICROSEC(&diff); + timessub(&stats->end_time, &stats->start_time, &diff); + diff_us = TIMESPEC_TO_MICROSEC(&diff); if (!flows_total || !tcpr_ctx->iteration) return; diff --git a/src/tcpreplay.h b/src/tcpreplay.h index ddfaea8ce..1006843e2 100644 --- a/src/tcpreplay.h +++ b/src/tcpreplay.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcpreplay_api.c b/src/tcpreplay_api.c index d429b91b1..c4a412a48 100644 --- a/src/tcpreplay_api.c +++ b/src/tcpreplay_api.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -18,23 +18,23 @@ * along with the Tcpreplay Suite. If not, see . */ -#include "config.h" +#include "tcpreplay_api.h" #include "defines.h" +#include "config.h" #include "common.h" - +#include "replay.h" +#include "send_packets.h" +#include "sleep.h" #include +#include #include +#include #include #include #include #include +#include #include -#include -#include - -#include "tcpreplay_api.h" -#include "send_packets.h" -#include "replay.h" #ifdef TCPREPLAY_EDIT #include "tcpreplay_edit_opts.h" @@ -166,6 +166,7 @@ tcpreplay_post_args(tcpreplay_t *ctx, int argc) options->loop = OPT_VALUE_LOOP; options->loopdelay_ms = OPT_VALUE_LOOPDELAY_MS; + options->loopdelay_ns = OPT_VALUE_LOOPDELAY_NS; if (HAVE_OPT(LIMIT)) options->limit_send = OPT_VALUE_LIMIT; @@ -208,6 +209,9 @@ tcpreplay_post_args(tcpreplay_t *ctx, int argc) options->maxsleep.tv_nsec = (OPT_VALUE_MAXSLEEP % 1000) * 1000 * 1000; } + if (HAVE_OPT(SUPPRESS_WARNINGS)) + print_warnings = 0; + #ifdef ENABLE_VERBOSE if (HAVE_OPT(VERBOSE)) options->verbose = 1; @@ -265,6 +269,15 @@ tcpreplay_post_args(tcpreplay_t *ctx, int argc) #endif } + if (HAVE_OPT(XDP)) { +#ifdef HAVE_LIBXDP + options->xdp = 1; + ctx->sp_type = SP_TYPE_LIBXDP; +#else + err(-1, "--xdp feature was not compiled in. See INSTALL."); +#endif + } + if (HAVE_OPT(UNIQUE_IP)) options->unique_ip = 1; @@ -358,7 +371,9 @@ tcpreplay_post_args(tcpreplay_t *ctx, int argc) ret = -1; goto out; } - +#ifdef HAVE_LIBXDP + ctx->intf1->batch_size = OPT_VALUE_XDP_BATCH_SIZE; +#endif #if defined HAVE_NETMAP ctx->intf1->netmap_delay = ctx->options->netmap_delay; #endif @@ -429,6 +444,15 @@ tcpreplay_close(tcpreplay_t *ctx) assert(ctx->options); options = ctx->options; +#ifdef HAVE_LIBXDP + if (ctx->intf1->handle_type == SP_TYPE_LIBXDP) { + free_umem_and_xsk(ctx->intf1); + if (ctx->intf2) { + free_umem_and_xsk(ctx->intf2); + } + } +#endif + safe_free(options->intf1_name); safe_free(options->intf2_name); sendpacket_close(ctx->intf1); @@ -895,24 +919,24 @@ tcpreplay_get_failed(tcpreplay_t *ctx) } /** - * \brief returns a pointer to the timeval structure of when replay first started + * \brief returns a pointer to the timespec structure of when replay first started */ -const struct timeval * +const struct timespec * tcpreplay_get_start_time(tcpreplay_t *ctx) { assert(ctx); - TIMEVAL_SET(&ctx->static_stats.start_time, &ctx->stats.start_time); + TIMESPEC_SET(&ctx->static_stats.start_time, &ctx->stats.start_time); return &ctx->static_stats.start_time; } /** - * \brief returns a pointer to the timeval structure of when replay finished + * \brief returns a pointer to the timespec structure of when replay finished */ -const struct timeval * +const struct timespec * tcpreplay_get_end_time(tcpreplay_t *ctx) { assert(ctx); - TIMEVAL_SET(&ctx->static_stats.end_time, &ctx->stats.end_time); + TIMESPEC_SET(&ctx->static_stats.end_time, &ctx->stats.end_time); return &ctx->static_stats.end_time; } @@ -1099,6 +1123,7 @@ tcpreplay_prepare(tcpreplay_t *ctx) return ret; } +static bool apply_loop_delay(tcpreplay_t *ctx); /** * \brief sends the traffic out the interfaces * @@ -1149,14 +1174,20 @@ tcpreplay_replay(tcpreplay_t *ctx) if ((rcode = tcpr_replay_index(ctx)) < 0) return rcode; if (ctx->options->loop > 0) { - if (!ctx->abort && ctx->options->loopdelay_ms > 0) { - usleep(ctx->options->loopdelay_ms * 1000); - gettimeofday(&ctx->stats.end_time, NULL); - } + if (apply_loop_delay(ctx)) + get_current_time(&ctx->stats.end_time); - if (ctx->options->stats == 0) + if (ctx->options->stats == 0) { packet_stats(&ctx->stats); + } + } +#ifdef HAVE_LIBXDP + sendpacket_t *sp = ctx->intf1; + if (sp->handle_type == SP_TYPE_LIBXDP) { + sp->xsk_info->tx.cached_prod = 0; + sp->xsk_info->tx.cached_cons = sp->tx_size; } +#endif } } else { while (!ctx->abort) { /* loop forever unless user aborts */ @@ -1171,10 +1202,8 @@ tcpreplay_replay(tcpreplay_t *ctx) if ((rcode = tcpr_replay_index(ctx)) < 0) return rcode; - if (!ctx->abort && ctx->options->loopdelay_ms > 0) { - usleep(ctx->options->loopdelay_ms * 1000); - gettimeofday(&ctx->stats.end_time, NULL); - } + if (apply_loop_delay(ctx)) + get_current_time(&ctx->stats.end_time); if (ctx->options->stats == 0 && !ctx->abort) packet_stats(&ctx->stats); @@ -1356,3 +1385,55 @@ int tcpreplay_get_flow_expiry(tcpreplay_t *ctx) return ctx->options->flow_expiry; } + +bool +apply_loop_delay(tcpreplay_t *ctx) { + if (!ctx->abort && ctx->options->loopdelay_ms > 0) { + usleep(ctx->options->loopdelay_ms * 1000); + return true; + } + + if (!ctx->abort && ctx->options->loopdelay_ns > 0) { + struct timespec nap; + nap.tv_sec = 0; + nap.tv_nsec = ctx->options->loopdelay_ns; + nanosleep_sleep(NULL, &nap, &ctx->stats.end_time, NULL); + return true; + } + + return false; +} + +#ifdef HAVE_LIBXDP +void +delete_xsk_socket(struct xsk_socket *xsk) +{ + size_t desc_sz = sizeof(struct xdp_desc); + struct xdp_mmap_offsets off; + socklen_t optlen; + int err; + + if (!xsk) { + return; + } + + optlen = sizeof(off); + err = getsockopt(xsk->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen); + if (!err) { + if (xsk->rx) { + munmap(xsk->rx->ring - off.rx.desc, off.rx.desc + xsk->config.rx_size * desc_sz); + } + if (xsk->tx) { + munmap(xsk->tx->ring - off.tx.desc, off.tx.desc + xsk->config.tx_size * desc_sz); + } + } + close(xsk->fd); +} + +void +free_umem_and_xsk(sendpacket_t *sp) +{ + xsk_umem__delete(sp->xsk_info->umem->umem); + delete_xsk_socket(sp->xsk_info->xsk); +} +#endif /*HAVE_LIBXDP*/ diff --git a/src/tcpreplay_api.h b/src/tcpreplay_api.h index 88c03981e..c7154ed08 100644 --- a/src/tcpreplay_api.h +++ b/src/tcpreplay_api.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -33,6 +33,10 @@ #ifdef ENABLE_DMALLOC #include #endif +#ifdef HAVE_LIBXDP +#include +#include +#endif #ifdef __cplusplus extern "C" { @@ -99,6 +103,7 @@ typedef struct tcpreplay_opt_s { tcpreplay_speed_t speed; COUNTER loop; u_int32_t loopdelay_ms; + u_int32_t loopdelay_ns; int stats; bool use_pkthdr_len; @@ -144,6 +149,10 @@ typedef struct tcpreplay_opt_s { int netmap_delay; #endif +#ifdef HAVE_LIBXDP + int xdp; +#endif + /* print flow statistic */ bool flow_stats; int flow_expiry; @@ -178,6 +187,9 @@ typedef struct tcpreplay_s { uint32_t skip_packets; bool first_time; + /* fix header length */ + bool fixhdrlen; + /* counter stats */ tcpreplay_stats_t stats; tcpreplay_stats_t static_stats; /* stats returned by tcpreplay_get_stats() */ @@ -256,8 +268,8 @@ int tcpreplay_set_manual_callback(tcpreplay_t *ctx, tcpreplay_manual_callback); COUNTER tcpreplay_get_pkts_sent(tcpreplay_t *ctx); COUNTER tcpreplay_get_bytes_sent(tcpreplay_t *ctx); COUNTER tcpreplay_get_failed(tcpreplay_t *ctx); -const struct timeval *tcpreplay_get_start_time(tcpreplay_t *ctx); -const struct timeval *tcpreplay_get_end_time(tcpreplay_t *ctx); +const struct timespec *tcpreplay_get_start_time(tcpreplay_t *ctx); +const struct timespec *tcpreplay_get_end_time(tcpreplay_t *ctx); int tcpreplay_set_verbose(tcpreplay_t *, bool); int tcpreplay_set_tcpdump_args(tcpreplay_t *, char *); @@ -272,6 +284,10 @@ int tcpreplay_set_tcpdump(tcpreplay_t *, tcpdump_t *); void __tcpreplay_seterr(tcpreplay_t *ctx, const char *func, const int line, const char *file, const char *fmt, ...); void tcpreplay_setwarn(tcpreplay_t *ctx, const char *fmt, ...); +#ifdef HAVE_LIBXDP +void delete_xsk_socket(struct xsk_socket *xsk); +void free_umem_and_xsk(sendpacket_t *sp); +#endif #ifdef __cplusplus } #endif diff --git a/src/tcpreplay_opts.def b/src/tcpreplay_opts.def index a0036f764..c3ddfa9d2 100644 --- a/src/tcpreplay_opts.def +++ b/src/tcpreplay_opts.def @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -22,12 +22,12 @@ autogen definitions options; copyright = { - date = "2000-2022"; + date = "2000-2024"; owner = "Aaron Turner and Fred Klassen"; eaddr = "tcpreplay-users@lists.sourceforge.net"; type = gpl; author = <<- EOText -Copyright 2013-2022 Fred Klassen - AppNeta +Copyright 2013-2024 Fred Klassen - AppNeta Copyright 2000-2012 Aaron Turner @@ -320,6 +320,7 @@ flag = { flag = { name = loopdelay-ms; + flags-cant = loopdelay-ns; flags-must = loop; arg-type = number; arg-range = "0->"; @@ -328,6 +329,20 @@ flag = { doc = ""; }; +flag = { + name = loopdelay-ns; + flags-cant = loopdelay-ms; + flags-must = loop; + arg-type = number; + arg-range = "0->"; + descrip = "Delay between loops in nanoseconds"; + arg-default = 0; + doc = <<- EOText +By default, tcpreplay will use loop delay with microsecond accuracy (loopdelay-ms). +In order to use loop delay with nanosecond accuracy you need to use nano packet timing mode. +EOText; +}; + flag = { name = pktlen; max = 1; @@ -528,6 +543,20 @@ are fully up before netmap transmit. Requires netmap option. Default is 10 secon EOText; }; +flag = { + ifdef = HAVE_LIBXDP; + name = xdp; + descrip = "Write packets directly to AF_XDP enabled network adapter"; + doc = <<- EOText +This feature will detect AF_XDP capable network drivers on Linux systems +that have 'libxdp-dev' and 'libbpf-dev' installed. If detected, the network +stack is bypassed and packets are sent directly to an eBPF enabled driver directly. +This will allow you to achieve full line rates on commodity network adapters, similar to rates +achieved by commercial network traffic generators. +EOText; +}; + + flag = { name = no-flow-stats; descrip = "Suppress printing and tracking flow count, rates and expirations"; @@ -597,6 +626,16 @@ sending packets may cause equally long delays between printing statistics. EOText; }; +flag = { + ifdef = HAVE_LIBXDP; + name = xdp-batch-size; + arg-type = number; + arg-range = "1->4096"; + descrip = "The maximum number of packets that can be submitted to the AF_XDP TX ring at once"; + arg-default = 25; + doc = "Higher values may improve performance at the cost of accuracy"; +}; + flag = { name = version; value = V; @@ -611,7 +650,7 @@ flag = { fprintf(stderr, " (timestamp-trace)"); #endif fprintf(stderr, "\n"); - fprintf(stderr, "Copyright 2013-2022 by Fred Klassen - AppNeta\n"); + fprintf(stderr, "Copyright 2013-2024 by Fred Klassen - AppNeta\n"); fprintf(stderr, "Copyright 2000-2012 by Aaron Turner \n"); fprintf(stderr, "The entire Tcpreplay Suite is licensed under the GPLv3\n"); fprintf(stderr, "Cache file supported: %s\n", CACHEVERSION); @@ -656,6 +695,11 @@ flag = { fprintf(stderr, "Optional injection method: netmap\n"); #else fprintf(stderr, "Not compiled with netmap\n"); +#endif +#ifdef HAVE_LIBXDP + fprintf(stderr, "Optional injection method: AF_XDP\n"); +#else + fprintf(stderr, "Not compiled with AF_XDP\n"); #endif exit(0); @@ -675,3 +719,12 @@ flag = { EOHelp; doc = ""; }; + +flag = { + name = suppress-warnings; + value = w; + immediate; + descrip = "suppress printing warning messages"; + settable; + doc = ""; +}; diff --git a/src/tcprewrite.c b/src/tcprewrite.c index c9aa52c8c..d46e77d5c 100644 --- a/src/tcprewrite.c +++ b/src/tcprewrite.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -193,6 +193,9 @@ post_args(_U_ int argc, _U_ char *argv[]) warn("not configured with --enable-debug. Debugging disabled."); #endif + if (HAVE_OPT(SUPPRESS_WARNINGS)) + print_warnings = 0; + #ifdef ENABLE_VERBOSE if (HAVE_OPT(VERBOSE)) options.verbose = 1; diff --git a/src/tcprewrite.h b/src/tcprewrite.h index b88eb860c..bbbe5e007 100644 --- a/src/tcprewrite.h +++ b/src/tcprewrite.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tcprewrite_opts.def b/src/tcprewrite_opts.def index 42f341796..6ab383018 100644 --- a/src/tcprewrite_opts.def +++ b/src/tcprewrite_opts.def @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -21,12 +21,12 @@ autogen definitions options; copyright = { - date = "2000-2022"; + date = "2000-2024"; owner = "Aaron Turner and Fred Klassen"; eaddr = "tcpreplay-users@lists.sourceforge.net"; type = gpl; author = <<- EOText -Copyright 2013-2022 Fred Klassen - AppNeta +Copyright 2013-2024 Fred Klassen - AppNeta Copyright 2000-2012 Aaron Turner @@ -63,6 +63,8 @@ tcprewrite currently supports reading the following DLT types: @item @var{DLT_LINUX_SLL} aka Linux Cooked Socket @item +@var{DLT_LINUX_SLL2} aka Linux Cooked Socket v2 +@item @var{DLT_RAW} aka RAW IP @item @var{DLT_NULL} aka BSD Loopback @@ -249,7 +251,7 @@ flag = { fprintf(stderr, " (debug)"); #endif fprintf(stderr, "\n"); - fprintf(stderr, "Copyright 2013-2022 by Fred Klassen - AppNeta\n"); + fprintf(stderr, "Copyright 2013-2024 by Fred Klassen - AppNeta\n"); fprintf(stderr, "Copyright 2000-2012 by Aaron Turner \n"); fprintf(stderr, "The entire Tcpreplay Suite is licensed under the GPLv3\n"); fprintf(stderr, "Cache file supported: %s\n", CACHEVERSION); @@ -298,3 +300,12 @@ flag = { EOHelp; doc = ""; }; + +flag = { + name = suppress-warnings; + value = w; + immediate; + descrip = "suppress printing warning messages"; + settable; + doc = ""; +}; diff --git a/src/timestamp_trace.h b/src/timestamp_trace.h index 3aaa46af0..b6ff76529 100644 --- a/src/timestamp_trace.h +++ b/src/timestamp_trace.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as @@ -27,9 +27,9 @@ struct timestamp_trace_entry { COUNTER skip_length; COUNTER size; COUNTER bytes_sent; - COUNTER now_us; - COUNTER tx_us; - COUNTER next_tx_us; + COUNTER now_ns; + COUNTER tx_ns; + COUNTER next_tx_ns; COUNTER sent_bits; struct timeval timestamp; }; @@ -46,9 +46,9 @@ update_current_timestamp_trace_entry(COUNTER bytes_sent, COUNTER now_us, COUNTER return; if (!now_us) { - struct timeval now; - gettimeofday(&now, NULL); - now_us = TIMSTAMP_TO_MICROSEC(&now); + struct timespec now; + get_current_time(now); + now_us = TIMESPEC_TO_MICROSEC(&now); } timestamp_trace_entry_array[trace_num].bytes_sent = bytes_sent; @@ -58,7 +58,7 @@ update_current_timestamp_trace_entry(COUNTER bytes_sent, COUNTER now_us, COUNTER } static inline void -add_timestamp_trace_entry(COUNTER size, struct timeval *timestamp, COUNTER skip_length) +add_timestamp_trace_entry(COUNTER size, struct timespec *timestamp, COUNTER skip_length) { if (trace_num >= TRACE_MAX_ENTRIES) return; @@ -66,7 +66,7 @@ add_timestamp_trace_entry(COUNTER size, struct timeval *timestamp, COUNTER skip_ timestamp_trace_entry_array[trace_num].skip_length = skip_length; timestamp_trace_entry_array[trace_num].size = size; timestamp_trace_entry_array[trace_num].timestamp.tv_sec = timestamp->tv_sec; - timestamp_trace_entry_array[trace_num].timestamp.tv_usec = timestamp->tv_usec; + timestamp_trace_entry_array[trace_num].timestamp.tv_nsec = timestamp->tv_nsec; ++trace_num; } @@ -107,7 +107,7 @@ update_current_timestamp_trace_entry(COUNTER UNUSED(bytes_sent), COUNTER UNUSED(next_tx_us)) {} static inline void -add_timestamp_trace_entry(COUNTER UNUSED(size), struct timeval *UNUSED(timestamp), COUNTER UNUSED(skip_length)) +add_timestamp_trace_entry(COUNTER UNUSED(size), struct timespec *UNUSED(timestamp), COUNTER UNUSED(skip_length)) {} static inline void dump_timestamp_trace_array(const struct timeval *UNUSED(start), diff --git a/src/tree.c b/src/tree.c index 414458167..8c85ad01b 100644 --- a/src/tree.c +++ b/src/tree.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/src/tree.h b/src/tree.h index 9c6ff1b46..c4d104acf 100644 --- a/src/tree.h +++ b/src/tree.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2001-2010 Aaron Turner - * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as diff --git a/test/Makefile.am b/test/Makefile.am index 405438aac..19e85798a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -25,8 +25,10 @@ EXTRA_DIST = test.pcap test.auto_bridge test.auto_client test.auto_router \ test.rewrite_pnat test.rewrite_pad test.rewrite_trunc \ test.rewrite_mac test.rewrite_layer2 test.rewrite_config \ test.rewrite_skip test.rewrite_dltuser test.rewrite_dlthdlc \ - test.rewrite_vlan802.1ad test.rewrite_vlandel test.rewrite_efcs test.rewrite_1ttl \ - test.rewrite_2ttl test.rewrite_3ttl test.rewrite_enet_subsmac \ + test.rewrite_vlan802.1ad test.rewrite_vlandel test.rewrite_efcs \ + test.rewrite_1ttl test.rewrite_2ttl test.rewrite_3ttl \ + test.rewrite_1ttl-hdrfix test.rewrite_2ttl-hdrfix test.rewrite_3ttl-hdrfix \ + test.rewrite_enet_subsmac \ test.rewrite_mtutrunc test.rewrite_mac_seed test.rewrite_range_portmap \ test.rewrite_mac_seed_keep test.rewrite_l7fuzzing test.rewrite_sequence test.rewrite_fixcsum \ test.rewrite_fixlen_pad test.rewrite_fixlen_trunc test.rewrite_fixlen_del \ @@ -34,9 +36,11 @@ EXTRA_DIST = test.pcap test.auto_bridge test.auto_client test.auto_router \ test2.rewrite_pnat test2.rewrite_pad test2.rewrite_trunc \ test2.rewrite_mac test2.rewrite_layer2 test2.rewrite_config \ test2.rewrite_skip test2.rewrite_dltuser test2.rewrite_dlthdlc \ - test2.rewrite_vlan802.1ad test2.rewrite_vlandel test2.rewrite_efcs test2.rewrite_1ttl \ + test2.rewrite_vlan802.1ad test2.rewrite_vlandel test2.rewrite_efcs \ + test2.rewrite_1ttl test2.rewrite_2ttl test2.rewrite_3ttl \ + test2.rewrite_1ttl-hdrfix test2.rewrite_2ttl-hdrfix test2.rewrite_3ttl-hdrfix \ test2.rewrite_mtutrunc test2.rewrite_enet_subsmac \ - test2.rewrite_2ttl test2.rewrite_3ttl test.rewrite_tos test2.rewrite_tos \ + test.rewrite_tos test2.rewrite_tos \ test2.rewrite_enet_subsmac test2.rewrite_mac_seed \ test2.rewrite_range_portmap test2.rewrite_mac_seed_keep \ test2.rewrite_l7fuzzing test2.rewrite_sequence test2.rewrite_fixcsum \ @@ -125,6 +129,9 @@ standard_bigendian: $(TCPREWRITE) -i $(TEST_PCAP) -o test.rewrite_1ttl --ttl=58 $(TCPREWRITE) -i $(TEST_PCAP) -o test.rewrite_2ttl --ttl=+58 $(TCPREWRITE) -i $(TEST_PCAP) -o test.rewrite_3ttl --ttl=-58 + $(TCPREWRITE) -i $(TEST_PCAP) -o test.rewrite_1ttl-hdrfix --ttl=59 --fixhdrlen + $(TCPREWRITE) -i $(TEST_PCAP) -o test.rewrite_2ttl-hdrfix --ttl=+59 --fixhdrlen + $(TCPREWRITE) -i $(TEST_PCAP) -o test.rewrite_3ttl-hdrfix --ttl=-59 --fixhdrlen $(TCPREWRITE) -i $(TEST_PCAP) -o test.rewrite_mtutrunc --mtu-trunc --mtu=300 $(TCPREWRITE) -i $(TEST_PCAP) -o test.rewrite_l7fuzzing \ --fuzz-seed=42 --fuzz-factor=2 @@ -175,6 +182,9 @@ standard_littleendian: $(TCPREWRITE) -i $(TEST_PCAP) -o test2.rewrite_1ttl --ttl=58 $(TCPREWRITE) -i $(TEST_PCAP) -o test2.rewrite_2ttl --ttl=+58 $(TCPREWRITE) -i $(TEST_PCAP) -o test2.rewrite_3ttl --ttl=-58 + $(TCPREWRITE) -i $(TEST_PCAP) -o test2.rewrite_1ttl-hdrfix --ttl=59 --fixhdrlen + $(TCPREWRITE) -i $(TEST_PCAP) -o test2.rewrite_2ttl-hdrfix --ttl=+59 --fixhdrlen + $(TCPREWRITE) -i $(TEST_PCAP) -o test2.rewrite_3ttl-hdrfix --ttl=-59 --fixhdrlen $(TCPREWRITE) -i $(TEST_PCAP) -o test2.rewrite_mtutrunc --mtu-trunc --mtu=300 $(TCPREWRITE) -i $(TEST_PCAP) -o test2.rewrite_l7fuzzing \ --fuzz-seed=42 --fuzz-factor=2 @@ -191,12 +201,13 @@ tcpprep: auto_router auto_bridge auto_client auto_server auto_first cidr regex \ tcprewrite: rewrite_portmap rewrite_range_portmap rewrite_endpoint \ rewrite_pnat rewrite_trunc rewrite_pad rewrite_seed rewrite_mac \ rewrite_layer2 rewrite_config rewrite_skip rewrite_dltuser rewrite_dlthdlc \ - rewrite_vlan802.1ad rewrite_vlandel rewrite_efcs rewrite_1ttl rewrite_2ttl rewrite_3ttl \ + rewrite_vlan802.1ad rewrite_vlandel rewrite_efcs \ + rewrite_1ttl rewrite_2ttl rewrite_3ttl rewrite_1ttl-hdrfix rewrite_2ttl-hdrfix rewrite_3ttl-hdrfix \ rewrite_tos rewrite_mtutrunc rewrite_enet_subsmac rewrite_mac_seed \ rewrite_mac_seed_keep rewrite_l7fuzzing rewrite_sequence rewrite_fixcsum \ rewrite_fixlen_pad rewrite_fixlen_trunc rewrite_fixlen_del -tcpreplay: replay_basic replay_cache replay_pps replay_rate replay_top \ +tcpreplay: replay_basic replay_nano_timer replay_cache replay_pps replay_rate replay_top \ replay_config replay_multi replay_pps_multi replay_precache \ replay_stats replay_dualfile replay_maxsleep @@ -344,6 +355,12 @@ replay_basic: $(TCPREPLAY) $(ENABLE_DEBUG) -i $(nic1) -t $(TEST_PCAP) >> test.log 2>&1 if [ $? ] ; then $(PRINTF) "\t\t\t%s\n" "FAILED"; else $(PRINTF) "\t\t\t%s\n" "OK"; fi +replay_nano_timer: + $(PRINTF) "%s" "[tcpreplay] Nano timer test: " + $(PRINTF) "%s\n" "*** [tcpreplay] Nano timer test: " >> test.log + $(TCPREPLAY) $(ENABLE_DEBUG) -i $(nic1) --loop=2 --loopdelay-ns=125000000 -t $(TEST_PCAP) >> test.log 2>&1 + if [ $? ] ; then $(PRINTF) "\t\t\t%s\n" "FAILED"; else $(PRINTF) "\t\t\t%s\n" "OK"; fi + replay_cache: $(PRINTF) "%s" "[tcpreplay] Cache test: " $(PRINTF) "%s\n" "*** [tcpreplay] Cache test: " >> test.log @@ -632,6 +649,39 @@ else endif if [ $? ] ; then $(PRINTF) "\t\t\t%s\n" "FAILED"; else $(PRINTF) "\t\t\t%s\n" "OK"; fi +rewrite_1ttl-hdrfix: + $(PRINTF) "%s" "[tcprewrite] Force TTL with header fix: " + $(PRINTF) "%s\n" "*** [tcprewrite] Force TTL header fix: " >> test.log + $(TCPREWRITE) $(ENABLE_DEBUG) -i $(TEST_PCAP) -o test.$@1 --ttl=59 --fixhdrlen >> test.log 2>&1 +if WORDS_BIGENDIAN + diff $(srcdir)/test.$@ test.$@1 >> test.log 2>&1 +else + diff $(srcdir)/test2.$@ test.$@1 >> test.log 2>&1 +endif + if [ $? ] ; then $(PRINTF) "\t%s\n" "FAILED"; else $(PRINTF) "\t%s\n" "OK"; fi + +rewrite_2ttl-hdrfix: + $(PRINTF) "%s" "[tcprewrite] Increase TTL with header fix:" + $(PRINTF) "%s\n" "*** [tcprewrite] Increase TTL with header fix: " >> test.log + $(TCPREWRITE) $(ENABLE_DEBUG) -i $(TEST_PCAP) -o test.$@1 --ttl=+59 --fixhdrlen >> test.log 2>&1 +if WORDS_BIGENDIAN + diff $(srcdir)/test.$@ test.$@1 >> test.log 2>&1 +else + diff $(srcdir)/test2.$@ test.$@1 >> test.log 2>&1 +endif + if [ $? ] ; then $(PRINTF) "\t%s\n" "FAILED"; else $(PRINTF) "\t%s\n" "OK"; fi + +rewrite_3ttl-hdrfix: + $(PRINTF) "%s" "[tcprewrite] Reduce TTL with header fix: " + $(PRINTF) "%s\n" "*** [tcprewrite] Reduce TTL with header fix: " >> test.log + $(TCPREWRITE) $(ENABLE_DEBUG) -i $(TEST_PCAP) -o test.$@1 --ttl=-59 --fixhdrlen >> test.log 2>&1 +if WORDS_BIGENDIAN + diff $(srcdir)/test.$@ test.$@1 >> test.log 2>&1 +else + diff $(srcdir)/test2.$@ test.$@1 >> test.log 2>&1 +endif + if [ $? ] ; then $(PRINTF) "\t%s\n" "FAILED"; else $(PRINTF) "\t%s\n" "OK"; fi + rewrite_tos: $(PRINTF) "%s" "[tcprewrite] TOS test: " $(PRINTF) "%s\n" "*** [tcprewrite] TOS test: " >> test.log diff --git a/test/test.rewrite_1ttl b/test/test.rewrite_1ttl index 678358545..be666d94b 100644 Binary files a/test/test.rewrite_1ttl and b/test/test.rewrite_1ttl differ diff --git a/test/test.rewrite_1ttl-hdrfix b/test/test.rewrite_1ttl-hdrfix new file mode 100644 index 000000000..efb430a4f Binary files /dev/null and b/test/test.rewrite_1ttl-hdrfix differ diff --git a/test/test.rewrite_2ttl b/test/test.rewrite_2ttl index 8ad459994..63383b468 100644 Binary files a/test/test.rewrite_2ttl and b/test/test.rewrite_2ttl differ diff --git a/test/test.rewrite_2ttl-hdrfix b/test/test.rewrite_2ttl-hdrfix new file mode 100644 index 000000000..9a3257d28 Binary files /dev/null and b/test/test.rewrite_2ttl-hdrfix differ diff --git a/test/test.rewrite_3ttl b/test/test.rewrite_3ttl index 66662c01b..306647303 100644 Binary files a/test/test.rewrite_3ttl and b/test/test.rewrite_3ttl differ diff --git a/test/test.rewrite_3ttl-hdrfix b/test/test.rewrite_3ttl-hdrfix new file mode 100644 index 000000000..4c0b63096 Binary files /dev/null and b/test/test.rewrite_3ttl-hdrfix differ diff --git a/test/test.rewrite_config b/test/test.rewrite_config index 164e13b33..8c92c6e8a 100644 Binary files a/test/test.rewrite_config and b/test/test.rewrite_config differ diff --git a/test/test.rewrite_dlthdlc b/test/test.rewrite_dlthdlc index 3f2215101..61abbd45a 100644 Binary files a/test/test.rewrite_dlthdlc and b/test/test.rewrite_dlthdlc differ diff --git a/test/test.rewrite_dltuser b/test/test.rewrite_dltuser index 7b4fc8aa8..7074f81d8 100644 Binary files a/test/test.rewrite_dltuser and b/test/test.rewrite_dltuser differ diff --git a/test/test.rewrite_efcs b/test/test.rewrite_efcs index 470dc3778..b78682c8a 100644 Binary files a/test/test.rewrite_efcs and b/test/test.rewrite_efcs differ diff --git a/test/test.rewrite_endpoint b/test/test.rewrite_endpoint index 5121e5cfc..058ce28a5 100644 Binary files a/test/test.rewrite_endpoint and b/test/test.rewrite_endpoint differ diff --git a/test/test.rewrite_enet_subsmac b/test/test.rewrite_enet_subsmac index 4f49673d9..43080acd1 100644 Binary files a/test/test.rewrite_enet_subsmac and b/test/test.rewrite_enet_subsmac differ diff --git a/test/test.rewrite_fixcsum b/test/test.rewrite_fixcsum index f82948553..ae5a6e158 100644 Binary files a/test/test.rewrite_fixcsum and b/test/test.rewrite_fixcsum differ diff --git a/test/test.rewrite_fixlen_del b/test/test.rewrite_fixlen_del index 7c40ec511..274a5b451 100644 Binary files a/test/test.rewrite_fixlen_del and b/test/test.rewrite_fixlen_del differ diff --git a/test/test.rewrite_fixlen_pad b/test/test.rewrite_fixlen_pad index 7c40ec511..274a5b451 100644 Binary files a/test/test.rewrite_fixlen_pad and b/test/test.rewrite_fixlen_pad differ diff --git a/test/test.rewrite_fixlen_trunc b/test/test.rewrite_fixlen_trunc index 7c40ec511..274a5b451 100644 Binary files a/test/test.rewrite_fixlen_trunc and b/test/test.rewrite_fixlen_trunc differ diff --git a/test/test.rewrite_l7fuzzing b/test/test.rewrite_l7fuzzing index d6e022462..8b78e8f46 100644 Binary files a/test/test.rewrite_l7fuzzing and b/test/test.rewrite_l7fuzzing differ diff --git a/test/test.rewrite_layer2 b/test/test.rewrite_layer2 index be034dc6c..8f2efc971 100644 Binary files a/test/test.rewrite_layer2 and b/test/test.rewrite_layer2 differ diff --git a/test/test.rewrite_mac b/test/test.rewrite_mac index 15aa507f9..2380e1bcb 100644 Binary files a/test/test.rewrite_mac and b/test/test.rewrite_mac differ diff --git a/test/test.rewrite_mac_seed b/test/test.rewrite_mac_seed index 88e78b200..f39da310e 100644 Binary files a/test/test.rewrite_mac_seed and b/test/test.rewrite_mac_seed differ diff --git a/test/test.rewrite_mac_seed_keep b/test/test.rewrite_mac_seed_keep index 365140c7d..cc1675d2e 100644 Binary files a/test/test.rewrite_mac_seed_keep and b/test/test.rewrite_mac_seed_keep differ diff --git a/test/test.rewrite_mtutrunc b/test/test.rewrite_mtutrunc index f373dd01f..1e5c53843 100644 Binary files a/test/test.rewrite_mtutrunc and b/test/test.rewrite_mtutrunc differ diff --git a/test/test.rewrite_pad b/test/test.rewrite_pad index 7c40ec511..274a5b451 100644 Binary files a/test/test.rewrite_pad and b/test/test.rewrite_pad differ diff --git a/test/test.rewrite_pnat b/test/test.rewrite_pnat index 1a8d42fac..a8f82a479 100644 Binary files a/test/test.rewrite_pnat and b/test/test.rewrite_pnat differ diff --git a/test/test.rewrite_portmap b/test/test.rewrite_portmap index b519c2589..7da93c828 100644 Binary files a/test/test.rewrite_portmap and b/test/test.rewrite_portmap differ diff --git a/test/test.rewrite_range_portmap b/test/test.rewrite_range_portmap index c9a1c82ad..e66130a58 100644 Binary files a/test/test.rewrite_range_portmap and b/test/test.rewrite_range_portmap differ diff --git a/test/test.rewrite_seed b/test/test.rewrite_seed index 6204f570f..a92db11e6 100644 Binary files a/test/test.rewrite_seed and b/test/test.rewrite_seed differ diff --git a/test/test.rewrite_sequence b/test/test.rewrite_sequence index d19f23f41..48d97554c 100644 Binary files a/test/test.rewrite_sequence and b/test/test.rewrite_sequence differ diff --git a/test/test.rewrite_skip b/test/test.rewrite_skip index d4e348cbd..13632b78d 100644 Binary files a/test/test.rewrite_skip and b/test/test.rewrite_skip differ diff --git a/test/test.rewrite_tos b/test/test.rewrite_tos index fb56b6761..999b51b57 100644 Binary files a/test/test.rewrite_tos and b/test/test.rewrite_tos differ diff --git a/test/test.rewrite_trunc b/test/test.rewrite_trunc index 7c40ec511..274a5b451 100644 Binary files a/test/test.rewrite_trunc and b/test/test.rewrite_trunc differ diff --git a/test/test.rewrite_vlan802.1ad b/test/test.rewrite_vlan802.1ad index f3fcc1bee..90fddeeab 100644 Binary files a/test/test.rewrite_vlan802.1ad and b/test/test.rewrite_vlan802.1ad differ diff --git a/test/test.rewrite_vlandel b/test/test.rewrite_vlandel index 7c40ec511..274a5b451 100644 Binary files a/test/test.rewrite_vlandel and b/test/test.rewrite_vlandel differ diff --git a/test/test2.rewrite_1ttl b/test/test2.rewrite_1ttl index f1d77f940..98aa4eac4 100644 Binary files a/test/test2.rewrite_1ttl and b/test/test2.rewrite_1ttl differ diff --git a/test/test2.rewrite_1ttl-hdrfix b/test/test2.rewrite_1ttl-hdrfix new file mode 100644 index 000000000..3fefe3afb Binary files /dev/null and b/test/test2.rewrite_1ttl-hdrfix differ diff --git a/test/test2.rewrite_2ttl b/test/test2.rewrite_2ttl index a96794836..4b196073f 100644 Binary files a/test/test2.rewrite_2ttl and b/test/test2.rewrite_2ttl differ diff --git a/test/test2.rewrite_2ttl-hdrfix b/test/test2.rewrite_2ttl-hdrfix new file mode 100644 index 000000000..2e6570f04 Binary files /dev/null and b/test/test2.rewrite_2ttl-hdrfix differ diff --git a/test/test2.rewrite_3ttl b/test/test2.rewrite_3ttl index e820d35ea..d38cf60a7 100644 Binary files a/test/test2.rewrite_3ttl and b/test/test2.rewrite_3ttl differ diff --git a/test/test2.rewrite_3ttl-hdrfix b/test/test2.rewrite_3ttl-hdrfix new file mode 100644 index 000000000..73d078b1a Binary files /dev/null and b/test/test2.rewrite_3ttl-hdrfix differ diff --git a/test/test2.rewrite_config b/test/test2.rewrite_config index a6a834fec..238ee7e58 100644 Binary files a/test/test2.rewrite_config and b/test/test2.rewrite_config differ diff --git a/test/test2.rewrite_dlthdlc b/test/test2.rewrite_dlthdlc index 0c0472475..01c351cb7 100644 Binary files a/test/test2.rewrite_dlthdlc and b/test/test2.rewrite_dlthdlc differ diff --git a/test/test2.rewrite_dltuser b/test/test2.rewrite_dltuser index 0b605a59f..ce15642fa 100644 Binary files a/test/test2.rewrite_dltuser and b/test/test2.rewrite_dltuser differ diff --git a/test/test2.rewrite_efcs b/test/test2.rewrite_efcs index fd74a0a24..3b5cec1b2 100644 Binary files a/test/test2.rewrite_efcs and b/test/test2.rewrite_efcs differ diff --git a/test/test2.rewrite_endpoint b/test/test2.rewrite_endpoint index ba365c740..58d7b43f4 100644 Binary files a/test/test2.rewrite_endpoint and b/test/test2.rewrite_endpoint differ diff --git a/test/test2.rewrite_enet_subsmac b/test/test2.rewrite_enet_subsmac index 987bfa6dd..f3fc64f49 100644 Binary files a/test/test2.rewrite_enet_subsmac and b/test/test2.rewrite_enet_subsmac differ diff --git a/test/test2.rewrite_fixcsum b/test/test2.rewrite_fixcsum index d28557726..71f2d61f3 100644 Binary files a/test/test2.rewrite_fixcsum and b/test/test2.rewrite_fixcsum differ diff --git a/test/test2.rewrite_fixlen_del b/test/test2.rewrite_fixlen_del index cae178213..50f1291ca 100644 Binary files a/test/test2.rewrite_fixlen_del and b/test/test2.rewrite_fixlen_del differ diff --git a/test/test2.rewrite_fixlen_pad b/test/test2.rewrite_fixlen_pad index cae178213..50f1291ca 100644 Binary files a/test/test2.rewrite_fixlen_pad and b/test/test2.rewrite_fixlen_pad differ diff --git a/test/test2.rewrite_fixlen_trunc b/test/test2.rewrite_fixlen_trunc index cae178213..50f1291ca 100644 Binary files a/test/test2.rewrite_fixlen_trunc and b/test/test2.rewrite_fixlen_trunc differ diff --git a/test/test2.rewrite_l7fuzzing b/test/test2.rewrite_l7fuzzing index 4af63622d..4a2ef290b 100644 Binary files a/test/test2.rewrite_l7fuzzing and b/test/test2.rewrite_l7fuzzing differ diff --git a/test/test2.rewrite_layer2 b/test/test2.rewrite_layer2 index c961f9e16..885d6b737 100644 Binary files a/test/test2.rewrite_layer2 and b/test/test2.rewrite_layer2 differ diff --git a/test/test2.rewrite_mac b/test/test2.rewrite_mac index da59e7cec..fd1f182e7 100644 Binary files a/test/test2.rewrite_mac and b/test/test2.rewrite_mac differ diff --git a/test/test2.rewrite_mac_seed b/test/test2.rewrite_mac_seed index c5b9a34a1..1792f8ef8 100644 Binary files a/test/test2.rewrite_mac_seed and b/test/test2.rewrite_mac_seed differ diff --git a/test/test2.rewrite_mac_seed_keep b/test/test2.rewrite_mac_seed_keep index 92c9bb2ee..1bc55e4d3 100644 Binary files a/test/test2.rewrite_mac_seed_keep and b/test/test2.rewrite_mac_seed_keep differ diff --git a/test/test2.rewrite_mtutrunc b/test/test2.rewrite_mtutrunc index 22621728b..242481f6f 100644 Binary files a/test/test2.rewrite_mtutrunc and b/test/test2.rewrite_mtutrunc differ diff --git a/test/test2.rewrite_pad b/test/test2.rewrite_pad index cae178213..50f1291ca 100644 Binary files a/test/test2.rewrite_pad and b/test/test2.rewrite_pad differ diff --git a/test/test2.rewrite_pnat b/test/test2.rewrite_pnat index 8e6473c48..8af339637 100644 Binary files a/test/test2.rewrite_pnat and b/test/test2.rewrite_pnat differ diff --git a/test/test2.rewrite_portmap b/test/test2.rewrite_portmap index a3883cc2e..6129aef61 100644 Binary files a/test/test2.rewrite_portmap and b/test/test2.rewrite_portmap differ diff --git a/test/test2.rewrite_range_portmap b/test/test2.rewrite_range_portmap index 391756ff8..558bbb76d 100644 Binary files a/test/test2.rewrite_range_portmap and b/test/test2.rewrite_range_portmap differ diff --git a/test/test2.rewrite_seed b/test/test2.rewrite_seed index acd725e24..c1198b22d 100644 Binary files a/test/test2.rewrite_seed and b/test/test2.rewrite_seed differ diff --git a/test/test2.rewrite_sequence b/test/test2.rewrite_sequence index 93524b169..d7db32792 100644 Binary files a/test/test2.rewrite_sequence and b/test/test2.rewrite_sequence differ diff --git a/test/test2.rewrite_skip b/test/test2.rewrite_skip index ec290c989..9df112b6f 100644 Binary files a/test/test2.rewrite_skip and b/test/test2.rewrite_skip differ diff --git a/test/test2.rewrite_tos b/test/test2.rewrite_tos index e3554d982..fe38d666d 100644 Binary files a/test/test2.rewrite_tos and b/test/test2.rewrite_tos differ diff --git a/test/test2.rewrite_trunc b/test/test2.rewrite_trunc index cae178213..50f1291ca 100644 Binary files a/test/test2.rewrite_trunc and b/test/test2.rewrite_trunc differ diff --git a/test/test2.rewrite_vlan802.1ad b/test/test2.rewrite_vlan802.1ad index d91c095aa..40f1e128b 100644 Binary files a/test/test2.rewrite_vlan802.1ad and b/test/test2.rewrite_vlan802.1ad differ diff --git a/test/test2.rewrite_vlandel b/test/test2.rewrite_vlandel index cae178213..50f1291ca 100644 Binary files a/test/test2.rewrite_vlandel and b/test/test2.rewrite_vlandel differ