Browse Source

Import upstream version 4.4.0

Fred Klassen 6 months ago
parent
commit
661da7d41e
100 changed files with 2003 additions and 10176 deletions
  1. 8 4
      Makefile.in
  2. 7 9050
      aclocal.m4
  3. 61 103
      configure
  4. 48 94
      configure.ac
  5. 14 0
      docs/CHANGELOG
  6. 3 0
      docs/CREDIT
  7. 6 3
      docs/Makefile.in
  8. 1 1
      docs/TODO
  9. 6 3
      lib/Makefile.in
  10. 24 28
      lib/strlcat.c
  11. 19 24
      lib/strlcpy.c
  12. 1 1
      lib/strlcpy.h
  13. 6 3
      libopts/Makefile.in
  14. 588 0
      m4/libopts.m4
  15. 41 0
      m4/stdnoreturn.m4
  16. 6 3
      scripts/Makefile.in
  17. 6 3
      src/Makefile.in
  18. 1 1
      src/bridge.c
  19. 1 1
      src/bridge.h
  20. 1 1
      src/common.h
  21. 6 3
      src/common/Makefile.in
  22. 1 1
      src/common/cache.c
  23. 1 1
      src/common/cache.h
  24. 5 7
      src/common/cidr.c
  25. 1 1
      src/common/cidr.h
  26. 1 1
      src/common/err.c
  27. 1 1
      src/common/err.h
  28. 1 1
      src/common/fakepcap.c
  29. 1 1
      src/common/fakepcap.h
  30. 1 1
      src/common/fakepcapnav.c
  31. 1 1
      src/common/fakepcapnav.h
  32. 35 92
      src/common/flows.c
  33. 1 1
      src/common/flows.h
  34. 348 212
      src/common/get.c
  35. 19 2
      src/common/get.h
  36. 1 1
      src/common/git_version.c
  37. 1 1
      src/common/interface.c
  38. 1 1
      src/common/interface.h
  39. 1 1
      src/common/list.c
  40. 1 1
      src/common/list.h
  41. 1 1
      src/common/mac.c
  42. 1 1
      src/common/mac.h
  43. 1 1
      src/common/pcap_dlt.h
  44. 1 1
      src/common/sendpacket.c
  45. 1 1
      src/common/sendpacket.h
  46. 1 1
      src/common/services.c
  47. 1 1
      src/common/services.h
  48. 1 1
      src/common/tcpdump.c
  49. 1 1
      src/common/tcpdump.h
  50. 1 1
      src/common/timer.c
  51. 1 1
      src/common/timer.h
  52. 1 1
      src/common/utils.c
  53. 1 3
      src/common/utils.h
  54. 1 1
      src/common/xX.c
  55. 1 1
      src/common/xX.h
  56. 3 3
      src/config.h.in
  57. 6 3
      src/defines.h
  58. 6 3
      src/defines.h.in
  59. 6 3
      src/fragroute/Makefile.in
  60. 1 1
      src/fragroute/fragroute.c
  61. 1 1
      src/fragroute/fragroute.h
  62. 1 1
      src/replay.c
  63. 1 1
      src/replay.h
  64. 37 37
      src/send_packets.c
  65. 1 1
      src/send_packets.h
  66. 1 1
      src/signal_handler.c
  67. 1 1
      src/signal_handler.h
  68. 1 1
      src/sleep.c
  69. 1 1
      src/sleep.h
  70. 24 4
      src/tcpbridge.1
  71. 1 1
      src/tcpbridge.c
  72. 1 1
      src/tcpbridge.h
  73. 215 184
      src/tcpbridge_opts.c
  74. 4 4
      src/tcpbridge_opts.def
  75. 34 32
      src/tcpbridge_opts.h
  76. 1 1
      src/tcpcapinfo.1
  77. 1 1
      src/tcpcapinfo.c
  78. 1 1
      src/tcpcapinfo_opts.c
  79. 2 2
      src/tcpcapinfo_opts.def
  80. 6 3
      src/tcpedit/Makefile.in
  81. 19 24
      src/tcpedit/checksum.c
  82. 1 1
      src/tcpedit/checksum.h
  83. 1 1
      src/tcpedit/dlt.c
  84. 1 1
      src/tcpedit/dlt.h
  85. 5 44
      src/tcpedit/edit_packet.c
  86. 10 1
      src/tcpedit/edit_packet.h
  87. 6 2
      src/tcpedit/fuzzing.c
  88. 1 1
      src/tcpedit/parse_args.c
  89. 1 1
      src/tcpedit/parse_args.h
  90. 1 1
      src/tcpedit/plugins.h
  91. 251 123
      src/tcpedit/plugins/dlt_en10mb/en10mb.c
  92. 6 2
      src/tcpedit/plugins/dlt_en10mb/en10mb.h
  93. 1 1
      src/tcpedit/plugins/dlt_en10mb/en10mb_api.c
  94. 1 1
      src/tcpedit/plugins/dlt_en10mb/en10mb_api.h
  95. 27 1
      src/tcpedit/plugins/dlt_en10mb/en10mb_opts.def
  96. 8 1
      src/tcpedit/plugins/dlt_en10mb/en10mb_types.h
  97. 8 4
      src/tcpedit/plugins/dlt_hdlc/hdlc.c
  98. 6 2
      src/tcpedit/plugins/dlt_hdlc/hdlc.h
  99. 1 1
      src/tcpedit/plugins/dlt_hdlc/hdlc_api.c
  100. 0 0
      src/tcpedit/plugins/dlt_hdlc/hdlc_api.h

+ 8 - 4
Makefile.in

@@ -90,9 +90,12 @@ host_triplet = @host@
 target_triplet = @target@
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/libopts/m4/libopts.m4 \
-	$(top_srcdir)/libopts/m4/stdnoreturn.m4 \
-	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/m4/libopts.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/stdnoreturn.m4 $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
@@ -165,7 +168,8 @@ am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/doxygen.cfg.in \
 	$(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \
 	$(top_srcdir)/config/missing INSTALL config/ar-lib \
 	config/compile config/config.guess config/config.sub \
-	config/install-sh config/ltmain.sh config/missing
+	config/depcomp config/install-sh config/ltmain.sh \
+	config/missing
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)

File diff suppressed because it is too large
+ 7 - 9050
aclocal.m4


+ 61 - 103
configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for tcpreplay 4.3.4.
+# Generated by GNU Autoconf 2.69 for tcpreplay 4.4.0.
 #
 # Report bugs to <https://github.com/appneta/tcpreplay/issues>.
 #
@@ -590,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='tcpreplay'
 PACKAGE_TARNAME='tcpreplay'
-PACKAGE_VERSION='4.3.4'
-PACKAGE_STRING='tcpreplay 4.3.4'
+PACKAGE_VERSION='4.4.0'
+PACKAGE_STRING='tcpreplay 4.4.0'
 PACKAGE_BUGREPORT='https://github.com/appneta/tcpreplay/issues'
 PACKAGE_URL='http://tcpreplay.sourceforge.net/'
 
@@ -833,7 +833,7 @@ ac_user_opts='
 enable_option_checking
 enable_maintainer_mode
 with_dmalloc
-with_macosx_sdk
+with_macos_sdk
 with_pfring_lib
 enable_silent_rules
 enable_dependency_tracking
@@ -1445,7 +1445,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures tcpreplay 4.3.4 to adapt to many kinds of systems.
+\`configure' configures tcpreplay 4.4.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1517,7 +1517,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of tcpreplay 4.3.4:";;
+     short | recursive ) echo "Configuration of tcpreplay 4.4.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1576,10 +1576,7 @@ Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-dmalloc          use dmalloc, as in http://www.dmalloc.com
-  --with-macosx-sdk       Use a specific SDK for building.
-
-                          Usage:     --with-macosx-sdk=<version>
-                          e. g.: --with-macosx-sdk=10.8
+  --with-macos-sdk=VER    Specify the macOS SDK version to use.
 
   --with-pfring-lib       Use a specific PF_RING static library when using
                           PF_RING libpcap.
@@ -1692,7 +1689,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-tcpreplay configure 4.3.4
+tcpreplay configure 4.4.0
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2652,7 +2649,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by tcpreplay $as_me 4.3.4, which was
+It was created by tcpreplay $as_me 4.4.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3221,17 +3218,15 @@ fi
 
 
 
-# Check whether --with-macosx-sdk was given.
-if test "${with_macosx_sdk+set}" = set; then :
-  withval=$with_macosx_sdk;
+# Check whether --with-macos-sdk was given.
+if test "${with_macos_sdk+set}" = set; then :
+  withval=$with_macos_sdk;
 fi
 
 
-
-
 case "$host_os" in
     darwin*) # Mac OS X or iOS
-        # If no --with-macosx-sdk option is given, look for one
+        # If no --with-macos-sdk option is given, look for the latestq SDK
 
         # The intent is that for "most" Mac-based developers, a suitable
         # SDK will be found automatically without any configure options.
@@ -3242,22 +3237,48 @@ case "$host_os" in
         # To find a list of available version run `xcodebuild -showsdks`
 
         MULTIARCH=${host_cpu}-${host_os}
+        unset MACOSX_SDK_PATH
+
         { $as_echo "$as_me:${as_lineno-$LINENO}: checking what macOS compiler to use" >&5
 $as_echo_n "checking what macOS compiler to use... " >&6; }
 
-        for _macosx_sdk in $with_macosx_sdk 10.8 10.9 10.10 10.11 10.12 10.13 10.14 10.15 10.16 10.17 10.18 10.19 10.20 11.0 11.1 11.2 11.3 11.4 11.5; do
-            MACOSX_SDK_PATH=$(xcrun --sdk macosx${_macosx_sdk} --show-sdk-path 2> /dev/null)
-            if test -d "$MACOSX_SDK_PATH"; then
-                with_macosx_sdk="${_macosx_sdk}"
-                break
-            else
-                MACOSX_SDK_PATH=$(xcode-select -print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${_macosx_sdk}.sdk
-                if test -d "$MACOSX_SDK_PATH"; then
-                    with_macosx_sdk="${_macosx_sdk}"
-                    break
+        if test -n "$with_macos_sdk"; then
+            MACOSX_SDK_PATH=$(xcrun --sdk macosx${with_macos_sdk} --show-sdk-path 2> /dev/null)
+            if test -z "$MACOSX_SDK_PATH" ; then
+                as_fn_error $? "could not find SDK ${with_macos_sdk} for macos-${MULTIARCH}" "$LINENO" 5
+            fi
+        else
+            MACOSX_SDK_PATH=$(xcrun --show-sdk-path 2> /dev/null)
+            if test -z "$MACOSX_SDK_PATH" ; then
+                                for _macos_sdk_major in $(seq 15 -1 10); do
+                    for _macos_sdk_minor in $(seq 20 -1 0); do
+                        _macos_sdk_version=$_macos_sdk_major.$_macos_sdk_minor
+                        MACOSX_SDK_PATH=$(xcrun --sdk macosx${_macos_sdk_version} --show-sdk-path 2> /dev/null)
+                        if test -d "$_macos_sdk_path" ; then
+                            break 2
+                        fi
+                    done
+                done
+
+                                if test -z "$MACOSX_SDK_PATH"; then
+                    for _macos_sdk_major in $(seq 15 -1 10); do
+                        for _macos_sdk_minor in $(seq 20 -1 0); do
+                            _macos_sdk_version=$_macos_sdk_major.$_macos_sdk_minor
+                            MACOSX_SDK_PATH=$(xcode-select -print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${_macos_sdk_version}.sdk
+                            if test -d "$MACOSX_SDK_PATH"; then
+                                break 2
+                            fi
+
+                            MACOSX_SDK_PATH=$(xcode-select -print-path)/SDKs/MacOSX${_macos_sdk_version}.sdk
+                            if test -d "$MACOSX_SDK_PATH"; then
+                                break 2
+                            fi
+                        done
+                    done
                 fi
             fi
-        done
+        fi
+
         if test -d "$MACOSX_SDK_PATH"; then
             CC="$(xcrun -find clang) -m64 -isysroot $MACOSX_SDK_PATH"
             INSTALL_NAME_TOOL=$(xcrun -find install_name_tool)
@@ -3266,8 +3287,8 @@ $as_echo_n "checking what macOS compiler to use... " >&6; }
             STRIP=$(xcrun -find strip)
             LIBTOOL=$(xcrun -find libtool)
             RANLIB=$(xcrun -find ranlib)
-            { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+            { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${MACOSX_SDK_PATH}" >&5
+$as_echo "${MACOSX_SDK_PATH}" >&6; }
         else
             { $as_echo "$as_me:${as_lineno-$LINENO}: result: legacy" >&5
 $as_echo "legacy" >&6; }
@@ -3795,7 +3816,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='tcpreplay'
- VERSION='4.3.4'
+ VERSION='4.4.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -9342,6 +9363,10 @@ _lt_linker_boilerplate=`cat conftest.err`
 $RM -r conftest*
 
 
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
 if test -n "$compiler"; then
 
 lt_prog_compiler_no_builtin_flag=
@@ -19291,7 +19316,7 @@ fi
 
 done
 
-for ac_header in sys/io.h architecture/i386/pio.h sched.h
+for ac_header in sys/io.h architecture/i386/pio.h sched.h fts.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -22555,7 +22580,7 @@ if test "$cross_compiling" = yes; then
         NETMAP_SEARCH_DIRS=$trynetmapdir
     fi
 else
-    NETMAP_SEARCH_DIRS="$trynetmapdir /opt/netmap /usr/src/netmap-release /usr/src/netmap /usr/local/src/netmap-release /usr/local/src/netmap /usr/include"
+    NETMAP_SEARCH_DIRS="$trynetmapdir /opt/netmap /usr/src/netmap-release /usr/src/netmap /usr/local/src/netmap-release /usr/local/src/netmap /usr/include /usr/local/include"
 fi
 
 for testdir in $NETMAP_SEARCH_DIRS; do
@@ -23237,73 +23262,6 @@ fi
 fi # checking pcapnav version
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for requires strict byte alignment" >&5
-$as_echo_n "checking for requires strict byte alignment... " >&6; }
-if ${unaligned_cv_fail+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case "$host_cpu" in
-
-        # XXX: should also check that they don't do weird things (like on arm)
-        alpha*|arm*|hp*|mips*|sparc*|ia64)
-                unaligned_cv_fail=yes
-                ;;
-
-        *)
-        cat >conftest.c <<EOF
-        #include <sys/types.h>
-        #include <sys/wait.h>
-        #include <stdio.h>
-        unsigned char a[5] = { 1, 2, 3, 4, 5 };
-        main() {
-            unsigned int i;
-            pid_t pid;
-            int status;
-            /* avoid "core dumped" message */
-            pid = fork();
-            if (pid <  0)
-                exit(2);
-            if (pid > 0) {
-                /* parent */
-                pid = waitpid(pid, &status, 0);
-                if (pid < 0)
-                        exit(3);
-                exit(!WIFEXITED(status));
-            }
-            /* child */
-            i = *(unsigned int *)&a[1];
-            printf("%d\n", i);
-            exit(0);
-        }
-EOF
-        ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \
-            conftest.c $LIBS >/dev/null 2>&1
-        if test ! -x conftest ; then
-                        unaligned_cv_fail=yes
-        else
-            ./conftest >conftest.out
-            if test ! -s conftest.out ; then
-                unaligned_cv_fail=yes
-            else
-                unaligned_cv_fail=no
-            fi
-        fi
-        rm -f conftest* core core.conftest
-        ;;
-
-        esac
-
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $unaligned_cv_fail" >&5
-$as_echo "$unaligned_cv_fail" >&6; }
-if test $unaligned_cv_fail = yes ; then
-
-$as_echo "#define FORCE_ALIGN 1" >>confdefs.h
-
-fi
-
-
 tcpdump_path=no
 
 # Check whether --with-tcpdump was given.
@@ -25839,7 +25797,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by tcpreplay $as_me 4.3.4, which was
+This file was extended by tcpreplay $as_me 4.4.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -25906,7 +25864,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-tcpreplay config.status 4.3.4
+tcpreplay config.status 4.4.0
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 

+ 48 - 94
configure.ac

@@ -4,7 +4,7 @@ dnl $Id$
 AC_PREREQ([2.69])
 
 dnl Set version info here!
-AC_INIT([tcpreplay],[4.3.4],[https://github.com/appneta/tcpreplay/issues],[tcpreplay],[http://tcpreplay.sourceforge.net/])
+AC_INIT([tcpreplay],[4.4.0],[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)
@@ -44,27 +44,18 @@ fi
 AC_SUBST(CROSS_ARCH)
 AC_SUBST(CROSS_LD)
 
-dnl ============================================
-dnl MacOSX build and runtime environment options
-dnl ============================================
-
-AC_ARG_WITH(macosx-sdk,
-    AS_HELP_STRING([--with-macosx-sdk],
-        [Use a specific SDK for building.])
-    [
-                          Usage:     --with-macosx-sdk=<version>
-                          e. g.: --with-macosx-sdk=10.8
-    ],
-,)
-
 
 dnl ===========================
 dnl Check OS X SDK and compiler
 dnl ===========================
+AC_ARG_WITH([macos-sdk],
+            [AS_HELP_STRING([--with-macos-sdk=VER],
+                            [Specify the macOS SDK version to use.])]
+)
 
 case "$host_os" in
     darwin*) # Mac OS X or iOS
-        # If no --with-macosx-sdk option is given, look for one
+        # If no --with-macos-sdk option is given, look for the latestq SDK
 
         # The intent is that for "most" Mac-based developers, a suitable
         # SDK will be found automatically without any configure options.
@@ -75,21 +66,49 @@ case "$host_os" in
         # To find a list of available version run `xcodebuild -showsdks`
 
         MULTIARCH=${host_cpu}-${host_os}
+        unset MACOSX_SDK_PATH
+
         AC_MSG_CHECKING([what macOS compiler to use])
 
-        for _macosx_sdk in $with_macosx_sdk 10.8 10.9 10.10 10.11 10.12 10.13 10.14 10.15 10.16 10.17 10.18 10.19 10.20 11.0 11.1 11.2 11.3 11.4 11.5; do
-            MACOSX_SDK_PATH=$(xcrun --sdk macosx${_macosx_sdk} --show-sdk-path 2> /dev/null)
-            if test -d "$MACOSX_SDK_PATH"; then
-                with_macosx_sdk="${_macosx_sdk}"
-                break
-            else
-                MACOSX_SDK_PATH=$(xcode-select -print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${_macosx_sdk}.sdk
-                if test -d "$MACOSX_SDK_PATH"; then
-                    with_macosx_sdk="${_macosx_sdk}"
-                    break
+        if test -n "$with_macos_sdk"; then
+            MACOSX_SDK_PATH=$(xcrun --sdk macosx${with_macos_sdk} --show-sdk-path 2> /dev/null)
+            if test -z "$MACOSX_SDK_PATH" ; then
+                AC_MSG_ERROR([could not find SDK ${with_macos_sdk} for macos-${MULTIARCH}])
+            fi
+        else
+            MACOSX_SDK_PATH=$(xcrun --show-sdk-path 2> /dev/null)
+            if test -z "$MACOSX_SDK_PATH" ; then
+                dnl could not find a default SDK - search likely SDK versions
+                for _macos_sdk_major in $(seq 15 -1 10); do
+                    for _macos_sdk_minor in $(seq 20 -1 0); do
+                        _macos_sdk_version=$_macos_sdk_major.$_macos_sdk_minor
+                        MACOSX_SDK_PATH=$(xcrun --sdk macosx${_macos_sdk_version} --show-sdk-path 2> /dev/null)
+                        if test -d "$_macos_sdk_path" ; then
+                            break 2
+                        fi
+                    done
+                done
+
+                dnl could not find a default SDK - search disk for the latest SDK
+                if test -z "$MACOSX_SDK_PATH"; then
+                    for _macos_sdk_major in $(seq 15 -1 10); do
+                        for _macos_sdk_minor in $(seq 20 -1 0); do
+                            _macos_sdk_version=$_macos_sdk_major.$_macos_sdk_minor
+                            MACOSX_SDK_PATH=$(xcode-select -print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${_macos_sdk_version}.sdk
+                            if test -d "$MACOSX_SDK_PATH"; then
+                                break 2
+                            fi
+
+                            MACOSX_SDK_PATH=$(xcode-select -print-path)/SDKs/MacOSX${_macos_sdk_version}.sdk
+                            if test -d "$MACOSX_SDK_PATH"; then
+                                break 2
+                            fi
+                        done
+                    done
                 fi
             fi
-        done
+        fi
+
         if test -d "$MACOSX_SDK_PATH"; then
             CC="$(xcrun -find clang) -m64 -isysroot $MACOSX_SDK_PATH"
             INSTALL_NAME_TOOL=$(xcrun -find install_name_tool)
@@ -98,7 +117,7 @@ case "$host_os" in
             STRIP=$(xcrun -find strip)
             LIBTOOL=$(xcrun -find libtool)
             RANLIB=$(xcrun -find ranlib)
-            AC_MSG_RESULT([$CC])
+            AC_MSG_RESULT([${MACOSX_SDK_PATH}])
         else
             AC_MSG_RESULT([legacy])
         fi
@@ -333,7 +352,7 @@ AC_CHECK_HEADERS([fcntl.h stddef.h sys/socket.h  arpa/inet.h sys/time.h])
 AC_CHECK_HEADERS([signal.h string.h strings.h sys/types.h stdint.h sys/select.h])
 AC_CHECK_HEADERS([netinet/in.h netinet/in_systm.h poll.h sys/poll.h unistd.h sys/param.h])
 AC_CHECK_HEADERS([inttypes.h libintl.h sys/file.h sys/ioctl.h sys/systeminfo.h])
-AC_CHECK_HEADERS([sys/io.h architecture/i386/pio.h sched.h])
+AC_CHECK_HEADERS([sys/io.h architecture/i386/pio.h sched.h fts.h])
 AC_HEADER_STDBOOL
 
 dnl OpenBSD has special requirements
@@ -1266,7 +1285,7 @@ if test "$cross_compiling" = yes; then
         NETMAP_SEARCH_DIRS=$trynetmapdir
     fi
 else
-    NETMAP_SEARCH_DIRS="$trynetmapdir /opt/netmap /usr/src/netmap-release /usr/src/netmap /usr/local/src/netmap-release /usr/local/src/netmap /usr/include"
+    NETMAP_SEARCH_DIRS="$trynetmapdir /opt/netmap /usr/src/netmap-release /usr/src/netmap /usr/local/src/netmap-release /usr/local/src/netmap /usr/include /usr/local/include"
 fi
 
 for testdir in $NETMAP_SEARCH_DIRS; do
@@ -1680,71 +1699,6 @@ fi
 
 fi # checking pcapnav version
 
-
-dnl (shamelessly ripped off from libpcap)
-dnl Checks to see if unaligned memory accesses fail
-dnl
-dnl     FORCE_ALIGN (DEFINED)
-dnl
-AC_MSG_CHECKING(for requires strict byte alignment)
-AC_CACHE_VAL(unaligned_cv_fail,
-        [case "$host_cpu" in
-
-        # XXX: should also check that they don't do weird things (like on arm)
-        alpha*|arm*|hp*|mips*|sparc*|ia64)
-                unaligned_cv_fail=yes
-                ;;
-
-        *)
-        cat >conftest.c <<EOF
-        #include <sys/types.h>
-        #include <sys/wait.h>
-        #include <stdio.h>
-        unsigned char a[[5]] = { 1, 2, 3, 4, 5 };
-        main() {
-            unsigned int i;
-            pid_t pid;
-            int status;
-            /* avoid "core dumped" message */
-            pid = fork();
-            if (pid <  0)
-                exit(2);
-            if (pid > 0) {
-                /* parent */
-                pid = waitpid(pid, &status, 0);
-                if (pid < 0)
-                        exit(3);
-                exit(!WIFEXITED(status));
-            }
-            /* child */
-            i = *(unsigned int *)&a[[1]];
-            printf("%d\n", i);
-            exit(0);
-        }
-EOF
-        ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \
-            conftest.c $LIBS >/dev/null 2>&1
-        if test ! -x conftest ; then
-            dnl failed to compile for some reason
-            unaligned_cv_fail=yes
-        else
-            ./conftest >conftest.out
-            if test ! -s conftest.out ; then
-                unaligned_cv_fail=yes
-            else
-                unaligned_cv_fail=no
-            fi
-        fi
-        rm -f conftest* core core.conftest
-        ;;
-
-        esac
-    ])
-AC_MSG_RESULT($unaligned_cv_fail)
-if test $unaligned_cv_fail = yes ; then
-    AC_DEFINE([FORCE_ALIGN], [1], [Are we strictly aligned?])
-fi
-
 dnl ##################################################
 dnl # Check for tcpdump.
 dnl ##################################################

+ 14 - 0
docs/CHANGELOG

@@ -1,3 +1,17 @@
+06/19/2021 Version 4.4.0
+    - remove obsolete FORCE_ALIGN support to fix macOS 11 compile (#695)
+    - add a security policy document (#689)
+    - ability to specify directory of pcap files (#682)
+    - incorrect PPS rate for long-running sessions (#679)
+    - option --skipbroadcast not working (#677)
+    - revert #630 to fix --multiplier issues (#674)
+    - gcc 9.3 compiler warnings (#670)
+    - installed netmap not automatically detected (#669)
+    - latest macOS SDK selected by default (#668)
+    - heap-buffer-overflow with flow_decode() (#665)
+    - add feature VLAN Q-in-Q (#625)
+    - add feature update Ethernet MAC on multicast IP (#563)
+
 04/01/2021 Version 4.3.4
     - ASAN reports memory leaks while running tests (#662)
     - local libopts compiler warnings (#658)

+ 3 - 0
docs/CREDIT

@@ -104,3 +104,6 @@ Dave Craig <GitHub @davecraig>
 
 Vincent Bernat <GitHub @vincentbernat>
     - tcprewrite: fix DLT name for DLT_C_JNPR_ETHER in documentation
+
+Halver <GigHub @Halver>
+    - specify directories as files

+ 6 - 3
docs/Makefile.in

@@ -90,9 +90,12 @@ host_triplet = @host@
 target_triplet = @target@
 subdir = docs
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/libopts/m4/libopts.m4 \
-	$(top_srcdir)/libopts/m4/stdnoreturn.m4 \
-	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/m4/libopts.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/stdnoreturn.m4 $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)

+ 1 - 1
docs/TODO

@@ -76,7 +76,7 @@ TCPREWRITE:
     - others non-vanilla types?
     + Add tags?  Remove tags?  Change tags?
     - Tag only one side of the connection
-    - Support Q-in-Q tags:
+    + Support Q-in-Q tags:
           http://www.informit.com/articles/article.asp?p=101367&rl=1
     - Cisco's ISL trunking?
 

+ 6 - 3
lib/Makefile.in

@@ -92,9 +92,12 @@ host_triplet = @host@
 target_triplet = @target@
 subdir = lib
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/libopts/m4/libopts.m4 \
-	$(top_srcdir)/libopts/m4/stdnoreturn.m4 \
-	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/m4/libopts.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/stdnoreturn.m4 $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \

+ 24 - 28
lib/strlcat.c

@@ -1,7 +1,7 @@
-/*	$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $	*/
+/*	$OpenBSD: strlcat.c,v 1.19 2019/01/25 00:19:25 millert Exp $	*/
 
 /*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -16,44 +16,40 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char *rcsid = "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $";
-#endif /* LIBC_SCCS and not lint */
-
 #include <sys/types.h>
 #include <string.h>
 
 /*
- * Appends src to string dst of size siz (unlike strncat, siz is the
- * full size of dst, not space left).  At most siz-1 characters
- * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
- * Returns strlen(src) + MIN(siz, strlen(initial dst)).
- * If retval >= siz, truncation occurred.
+ * Appends src to string dst of size dsize (unlike strncat, dsize is the
+ * full size of dst, not space left).  At most dsize-1 characters
+ * will be copied.  Always NUL terminates (unless dsize <= strlen(dst)).
+ * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
+ * If retval >= dsize, truncation occurred.
  */
 size_t
-strlcat(char *dst, const char *src, size_t siz)
+strlcat(char *dst, const char *src, size_t dsize)
 {
-	register char *d = dst;
-	register const char *s = src;
-	register size_t n = siz;
+	const char *odst = dst;
+	const char *osrc = src;
+	size_t n = dsize;
 	size_t dlen;
 
-	/* Find the end of dst and adjust bytes left but don't go past end */
-	while (n-- != 0 && *d != '\0')
-		d++;
-	dlen = d - dst;
-	n = siz - dlen;
+	/* Find the end of dst and adjust bytes left but don't go past end. */
+	while (n-- != 0 && *dst != '\0')
+		dst++;
+	dlen = dst - odst;
+	n = dsize - dlen;
 
-	if (n == 0)
-		return(dlen + strlen(s));
-	while (*s != '\0') {
-		if (n != 1) {
-			*d++ = *s;
+	if (n-- == 0)
+		return(dlen + strlen(src));
+	while (*src != '\0') {
+		if (n != 0) {
+			*dst++ = *src;
 			n--;
 		}
-		s++;
+		src++;
 	}
-	*d = '\0';
+	*dst = '\0';
 
-	return(dlen + (s - src));	/* count does not include NUL */
+	return(dlen + (src - osrc));	/* count does not include NUL */
 }

+ 19 - 24
lib/strlcpy.c

@@ -1,7 +1,7 @@
-/*	$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $	*/
+/*	$OpenBSD: strlcpy.c,v 1.16 2019/01/25 00:19:25 millert Exp $	*/
 
 /*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -16,40 +16,35 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char *rcsid = "$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $";
-#endif /* LIBC_SCCS and not lint */
-
 #include <sys/types.h>
 #include <string.h>
 
 /*
- * Copy src to string dst of size siz.  At most siz-1 characters
- * will be copied.  Always NUL terminates (unless siz == 0).
- * Returns strlen(src); if retval >= siz, truncation occurred.
+ * Copy string src to buffer dst of size dsize.  At most dsize-1
+ * chars will be copied.  Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
  */
 size_t
-strlcpy(char *dst, const char *src, size_t siz)
+strlcpy(char *dst, const char *src, size_t dsize)
 {
-	register char *d = dst;
-	register const char *s = src;
-	register size_t n = siz;
+	const char *osrc = src;
+	size_t nleft = dsize;
 
-	/* Copy as many bytes as will fit */
-	if (n != 0 && --n != 0) {
-		do {
-			if ((*d++ = *s++) == 0)
+	/* Copy as many bytes as will fit. */
+	if (nleft != 0) {
+		while (--nleft != 0) {
+			if ((*dst++ = *src++) == '\0')
 				break;
-		} while (--n != 0);
+		}
 	}
 
-	/* Not enough room in dst, add NUL and traverse rest of src */
-	if (n == 0) {
-		if (siz != 0)
-			*d = '\0';		/* NUL-terminate dst */
-		while (*s++)
+	/* Not enough room in dst, add NUL and traverse rest of src. */
+	if (nleft == 0) {
+		if (dsize != 0)
+			*dst = '\0';		/* NUL-terminate dst */
+		while (*src++)
 			;
 	}
 
-	return(s - src - 1);	/* count does not include NUL */
+	return(src - osrc - 1);	/* count does not include NUL */
 }

+ 1 - 1
lib/strlcpy.h

@@ -1,6 +1,6 @@
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 6 - 3
libopts/Makefile.in

@@ -91,9 +91,12 @@ host_triplet = @host@
 target_triplet = @target@
 subdir = libopts
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/libopts/m4/libopts.m4 \
-	$(top_srcdir)/libopts/m4/stdnoreturn.m4 \
-	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/m4/libopts.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/stdnoreturn.m4 $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)

+ 588 - 0
m4/libopts.m4

@@ -0,0 +1,588 @@
+dnl  -*- buffer-read-only: t -*- vi: set ro:
+dnl
+dnl DO NOT EDIT THIS FILE   (libopts.m4)
+dnl
+dnl It has been AutoGen-ed
+dnl From the definitions    libopts.def
+dnl and the template file   conftest.tpl
+dnl
+dnl do always before generated macros:
+dnl
+AC_DEFUN([INVOKE_LIBOPTS_MACROS_FIRST],[
+  AC_HEADER_DIRENT
+
+  # =================
+  # AC_CHECK_HEADERS
+  # =================
+  AC_CHECK_HEADERS([ \
+      sys/mman.h    sys/param.h   sys/poll.h    sys/procset.h \
+      sys/select.h  sys/socket.h  sys/stropts.h sys/time.h \
+      sys/un.h      sys/wait.h    dlfcn.h       errno.h \
+      fcntl.h       libgen.h      libintl.h     memory.h \
+      netinet/in.h  setjmp.h      stdbool.h     sysexits.h \
+      unistd.h      utime.h])
+
+  AC_CHECK_HEADERS([stdarg.h     varargs.h],
+      [lo_have_arg_hdr=true;break],
+      [lo_have_arg_hdr=false])
+
+  AC_CHECK_HEADERS([string.h     strings.h],
+      [lo_have_str_hdr=true;break],
+      [lo_have_str_hdr=false])
+
+  AC_CHECK_HEADERS([limits.h     sys/limits.h  values.h],
+      [lo_have_lim_hdr=true;break],
+      [lo_have_lim_hdr=false])
+
+  AC_CHECK_HEADERS([inttypes.h   stdint.h],
+      [lo_have_typ_hdr=true;break],
+      [lo_have_typ_hdr=false])
+  gl_STDNORETURN_H
+
+  # ----------------------------------------------------------------------
+  # check for various programs used during the build.
+  # On OS/X, "wchar.h" needs "runetype.h" to work properly.
+  # ----------------------------------------------------------------------
+  AC_CHECK_HEADERS([runetype.h wchar.h], [], [],[
+  AC_INCLUDES_DEFAULT
+  #if HAVE_RUNETYPE_H
+  # include <runetype.h>
+  #endif
+  ])
+
+  AC_ARG_ENABLE([nls],
+  AS_HELP_STRING([--disable-nls],[disable nls support in libopts]))
+  AS_IF([test "x$enable_nls" != "xno" && \
+  test "X${ac_cv_header_libintl_h}" = Xyes], [
+  AC_DEFINE([ENABLE_NLS],[1],[nls support in libopts])])
+
+  # --------------------------------------------
+  # Verify certain entries from AC_CHECK_HEADERS
+  # --------------------------------------------
+  [${lo_have_arg_hdr} || \
+    ]AC_MSG_ERROR([you must have stdarg.h or varargs.h on your system])[
+
+  ${lo_have_str_hdr} || \
+    ]AC_MSG_ERROR([you must have string.h or strings.h on your system])[
+
+  ${lo_have_lim_hdr} || \
+    ]AC_MSG_ERROR(
+      [you must have one of limits.h, sys/limits.h or values.h])[
+
+  ${lo_have_typ_hdr} || \
+    ]AC_MSG_ERROR([you must have inttypes.h or stdint.h on your system])[
+
+  for f in sys_types sys_param sys_stat string errno stdlib memory setjmp
+  do eval as_ac_var=\${ac_cv_header_${f}_h}
+     test "X${as_ac_var}" = Xyes || {
+       ]AC_MSG_ERROR([you must have ${f}.h on your system])[
+     }
+  done
+  test "X${ac_cv_header_inttypes_h-no}" = Xyes || \
+    echo '#include <stdint.h>' > inttypes.h]
+
+  # ----------------------------------------------------------------------
+  # Checks for typedefs
+  # ----------------------------------------------------------------------
+  AC_CHECK_TYPES(wchar_t)
+  AC_CHECK_TYPES(wint_t, [], [], [
+    AC_INCLUDES_DEFAULT
+    #if HAVE_RUNETYPE_H
+    # include <runetype.h>
+    #endif
+    #if HAVE_WCHAR_H
+    # include <wchar.h>
+    #endif
+  ])
+  AC_CHECK_TYPES([int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
+  intptr_t, uintptr_t, uint_t, pid_t, size_t, ptrdiff_t])
+  AC_CHECK_SIZEOF(char *, 8)
+  AC_CHECK_SIZEOF(int,    4)
+  AC_CHECK_SIZEOF(long,   8)
+  AC_CHECK_SIZEOF(short,  2)
+
+  # ------------
+  # AC_CHECK_LIB
+  # ------------
+  AC_CHECK_LIB(gen, pathfind)
+  AC_CHECK_LIB(intl,gettext)
+  AC_FUNC_VPRINTF
+  AC_FUNC_FORK
+  AC_CHECK_FUNCS([mmap canonicalize_file_name snprintf strdup strchr \
+                 strrchr strsignal fchmod fstat chmod])
+  AC_PROG_SED
+  [while :
+  do
+      POSIX_SHELL=`which bash`
+      test -x "$POSIX_SHELL" && break
+      POSIX_SHELL=`which dash`
+      test -x "$POSIX_SHELL" && break
+      POSIX_SHELL=/usr/xpg4/bin/sh
+      test -x "$POSIX_SHELL" && break
+      POSIX_SHELL=`/bin/sh -c '
+          exec 2>/dev/null
+          if ! true ; then exit 1 ; fi
+          echo /bin/sh'`
+      test -x "$POSIX_SHELL" && break
+      ]AC_MSG_ERROR([cannot locate a working POSIX shell])[
+  done]
+  AC_DEFINE_UNQUOTED([POSIX_SHELL], ["${POSIX_SHELL}"],
+           [define to a working POSIX compliant shell])
+  AC_SUBST([POSIX_SHELL])
+])
+
+dnl
+dnl @synopsis  INVOKE_LIBOPTS_MACROS
+dnl
+dnl  This macro will invoke the AutoConf macros specified in libopts.def
+dnl  that have not been disabled with "omit-invocation".
+dnl
+AC_DEFUN([LIBOPTS_WITH_REGEX_HEADER],[
+  AC_ARG_WITH([regex-header],
+    AS_HELP_STRING([--with-regex-header], [a reg expr header is specified]),
+    [libopts_cv_with_regex_header=${with_regex_header}],
+    AC_CACHE_CHECK([whether a reg expr header is specified], libopts_cv_with_regex_header,
+      libopts_cv_with_regex_header=no)
+  ) # end of AC_ARG_WITH
+  if test "X${libopts_cv_with_regex_header}" != Xno
+  then
+    AC_DEFINE_UNQUOTED([REGEX_HEADER],[<${libopts_cv_with_regex_header}>])
+  else
+    AC_DEFINE([REGEX_HEADER],[<regex.h>],[name of regex header file])
+  fi
+
+]) # end of AC_DEFUN of LIBOPTS_WITH_REGEX_HEADER
+
+
+AC_DEFUN([LIBOPTS_WITHLIB_REGEX],[
+  AC_ARG_WITH([libregex],
+    AS_HELP_STRING([--with-libregex], [libregex installation prefix]),
+    [libopts_cv_with_libregex_root=${with_libregex}],
+    AC_CACHE_CHECK([whether with-libregex was specified], libopts_cv_with_libregex_root,
+      libopts_cv_with_libregex_root=no)
+  ) # end of AC_ARG_WITH libregex
+
+  if test "${with_libregex+set}" = set && \
+     test "X${withval}" = Xno
+  then ## disabled by request
+    libopts_cv_with_libregex_root=no
+    libopts_cv_with_libregex_cflags=no
+    libopts_cv_with_libregex_libs=no
+  else
+
+  AC_ARG_WITH([libregex-cflags],
+    AS_HELP_STRING([--with-libregex-cflags], [libregex compile flags]),
+    [libopts_cv_with_libregex_cflags=${with_libregex_cflags}],
+    AC_CACHE_CHECK([whether with-libregex-cflags was specified], libopts_cv_with_libregex_cflags,
+      libopts_cv_with_libregex_cflags=no)
+  ) # end of AC_ARG_WITH libregex-cflags
+
+  AC_ARG_WITH([libregex-libs],
+    AS_HELP_STRING([--with-libregex-libs], [libregex link command arguments]),
+    [libopts_cv_with_libregex_libs=${with_libregex_libs}],
+    AC_CACHE_CHECK([whether with-libregex-libs was specified], libopts_cv_with_libregex_libs,
+      libopts_cv_with_libregex_libs=no)
+  ) # end of AC_ARG_WITH libregex-libs
+
+  case "X${libopts_cv_with_libregex_cflags}" in
+  Xyes|Xno|X )
+    case "X${libopts_cv_with_libregex_root}" in
+    Xyes|Xno|X ) libopts_cv_with_libregex_cflags=no ;;
+    * ) libopts_cv_with_libregex_cflags=-I${libopts_cv_with_libregex_root}/include ;;
+    esac
+  esac
+  case "X${libopts_cv_with_libregex_libs}" in
+  Xyes|Xno|X )
+    case "X${libopts_cv_with_libregex_root}" in
+    Xyes|Xno|X ) libopts_cv_with_libregex_libs=no ;;
+    * )        libopts_cv_with_libregex_libs="-L${libopts_cv_with_libregex_root}/lib -lregex" ;;
+    esac
+  esac
+  libopts_save_CPPFLAGS="${CPPFLAGS}"
+  libopts_save_LIBS="${LIBS}"
+  case "X${libopts_cv_with_libregex_cflags}" in
+  Xyes|Xno|X )
+    libopts_cv_with_libregex_cflags="" ;;
+  * ) CPPFLAGS="${CPPFLAGS} ${libopts_cv_with_libregex_cflags}" ;;
+  esac
+  case "X${libopts_cv_with_libregex_libs}" in
+  Xyes|Xno|X )
+    libopts_cv_with_libregex_libs="" ;;
+  * )
+    LIBS="${LIBS} ${libopts_cv_with_libregex_libs}" ;;
+  esac
+  LIBREGEX_CFLAGS=""
+  LIBREGEX_LIBS=""
+  AC_MSG_CHECKING([whether libregex functions properly])
+  AC_CACHE_VAL([libopts_cv_with_libregex],[
+  AC_RUN_IFELSE([AC_LANG_SOURCE([@%:@include <stdio.h>
+@%:@include <stdlib.h>
+@%:@include <sys/types.h>
+@%:@include REGEX_HEADER
+static regex_t re;
+void comp_re(char const * pzPat) {
+  int res = regcomp( &re, pzPat, REG_EXTENDED|REG_ICASE|REG_NEWLINE );
+  if (res == 0) return;
+  exit( res ); }
+int main() {
+  regmatch_t m@<:@2@:>@;
+  comp_re( "^.*\@S|@"   );
+  comp_re( "()|no.*" );
+  comp_re( "."       );
+  if (regexec( &re, "X", 2, m, 0 ) != 0)  return 1;
+  if ((m@<:@0@:>@.rm_so != 0) || (m@<:@0@:>@.rm_eo != 1)) {
+    fputs( "error: regex -->.<-- did not match\n", stderr );
+    return 1;
+  }
+  return 0; }])],
+    [libopts_cv_with_libregex=yes], [libopts_cv_with_libregex=no],
+    [libopts_cv_with_libregex=no]) # end of AC_RUN_IFELSE 
+  ]) # end of AC_CACHE_VAL for libopts_cv_with_libregex
+  fi ## disabled by request
+  AC_MSG_RESULT([${libopts_cv_with_libregex}])
+  if test "X${libopts_cv_with_libregex}" != Xno
+  then
+    AC_DEFINE([WITH_LIBREGEX],[1],
+        [Define this if a working libregex can be found])
+  else
+    CPPFLAGS="${libopts_save_CPPFLAGS}"
+    LIBS="${libopts_save_LIBS}"
+    libopts_cv_with_libregex_root=no
+libopts_cv_with_libregex_cflags=no
+libopts_cv_with_libregex_libs=no
+libopts_cv_with_libregex=no
+  fi
+
+]) # end of AC_DEFUN of LIBOPTS_WITHLIB_REGEX
+
+
+AC_DEFUN([LIBOPTS_RUN_PATHFIND],[
+  AC_MSG_CHECKING([whether pathfind(3) works])
+  AC_CACHE_VAL([libopts_cv_run_pathfind],[
+  AC_RUN_IFELSE([AC_LANG_SOURCE([@%:@include <string.h>
+@%:@include <stdlib.h>
+int main (int argc, char ** argv) {
+   char * pz = pathfind( getenv( "PATH" ), "sh", "x" );
+   return (pz == 0) ? 1 : 0;
+}])],
+    [libopts_cv_run_pathfind=yes],[libopts_cv_run_pathfind=no],[libopts_cv_run_pathfind=no]
+  ) # end of RUN_IFELSE
+  ]) # end of AC_CACHE_VAL for libopts_cv_run_pathfind
+  AC_MSG_RESULT([${libopts_cv_run_pathfind}])
+  if test "X${libopts_cv_run_pathfind}" != Xno
+  then
+    AC_DEFINE([HAVE_PATHFIND],[1],
+        [Define this if pathfind(3) works])
+  fi
+
+]) # end of AC_DEFUN of LIBOPTS_RUN_PATHFIND
+
+
+AC_DEFUN([LIBOPTS_TEST_DEV_ZERO],[
+  AC_MSG_CHECKING([whether /dev/zero is readable device])
+  AC_CACHE_VAL([libopts_cv_test_dev_zero],[
+    libopts_cv_test_dev_zero=`exec 2> /dev/null
+dzero=\`ls -lL /dev/zero | egrep ^c......r\`
+test -z "${dzero}" && exit 1
+echo ${dzero}`
+    if test $? -ne 0 || test -z "$libopts_cv_test_dev_zero"
+    then libopts_cv_test_dev_zero=no
+    fi
+  ]) # end of CACHE_VAL of libopts_cv_test_dev_zero
+  AC_MSG_RESULT([${libopts_cv_test_dev_zero}])
+  if test "X${libopts_cv_test_dev_zero}" != Xno
+  then
+    AC_DEFINE([HAVE_DEV_ZERO],[1],
+        [Define this if /dev/zero is readable device])
+  fi
+
+]) # end of AC_DEFUN of LIBOPTS_TEST_DEV_ZERO
+
+
+AC_DEFUN([LIBOPTS_RUN_REALPATH],[
+  AC_MSG_CHECKING([whether we have a functional realpath(3C)])
+  AC_CACHE_VAL([libopts_cv_run_realpath],[
+  AC_RUN_IFELSE([AC_LANG_SOURCE([@%:@include <limits.h>
+@%:@include <stdlib.h>
+int main (int argc, char ** argv) {
+@%:@ifndef PATH_MAX
+choke me!!
+@%:@else
+   char zPath@<:@PATH_MAX+1@:>@;
+@%:@endif
+   char *pz = realpath(argv@<:@0@:>@, zPath);
+   return (pz == zPath) ? 0 : 1;
+}])],
+    [libopts_cv_run_realpath=yes],[libopts_cv_run_realpath=no],[libopts_cv_run_realpath=no]
+  ) # end of RUN_IFELSE
+  ]) # end of AC_CACHE_VAL for libopts_cv_run_realpath
+  AC_MSG_RESULT([${libopts_cv_run_realpath}])
+  if test "X${libopts_cv_run_realpath}" != Xno
+  then
+    AC_DEFINE([HAVE_REALPATH],[1],
+        [Define this if we have a functional realpath(3C)])
+  fi
+
+]) # end of AC_DEFUN of LIBOPTS_RUN_REALPATH
+
+
+AC_DEFUN([LIBOPTS_RUN_STRFTIME],[
+  AC_MSG_CHECKING([whether strftime() works])
+  AC_CACHE_VAL([libopts_cv_run_strftime],[
+  AC_RUN_IFELSE([AC_LANG_SOURCE([@%:@include <time.h>
+@%:@include <string.h>
+char t_buf@<:@ 64 @:>@;
+int main() {
+  static char const z@<:@@:>@ = "Thursday Aug 28 240";
+  struct tm tm;
+  tm.tm_sec   = 36;  /* seconds after the minute @<:@0, 61@:>@  */
+  tm.tm_min   = 44;  /* minutes after the hour @<:@0, 59@:>@ */
+  tm.tm_hour  = 12;  /* hour since midnight @<:@0, 23@:>@ */
+  tm.tm_mday  = 28;  /* day of the month @<:@1, 31@:>@ */
+  tm.tm_mon   =  7;  /* months since January @<:@0, 11@:>@ */
+  tm.tm_year  = 86;  /* years since 1900 */
+  tm.tm_wday  =  4;  /* days since Sunday @<:@0, 6@:>@ */
+  tm.tm_yday  = 239; /* days since January 1 @<:@0, 365@:>@ */
+  tm.tm_isdst =  1;  /* flag for daylight savings time */
+  strftime( t_buf, sizeof( t_buf ), "%A %b %d %j", &tm );
+  return (strcmp( t_buf, z ) != 0); }])],
+    [libopts_cv_run_strftime=yes],[libopts_cv_run_strftime=no],[libopts_cv_run_strftime=no]
+  ) # end of RUN_IFELSE
+  ]) # end of AC_CACHE_VAL for libopts_cv_run_strftime
+  AC_MSG_RESULT([${libopts_cv_run_strftime}])
+  if test "X${libopts_cv_run_strftime}" != Xno
+  then
+    AC_DEFINE([HAVE_STRFTIME],[1],
+        [Define this if strftime() works])
+  fi
+
+]) # end of AC_DEFUN of LIBOPTS_RUN_STRFTIME
+
+
+AC_DEFUN([LIBOPTS_RUN_FOPEN_BINARY],[
+  AC_MSG_CHECKING([whether fopen accepts "b" mode])
+  AC_CACHE_VAL([libopts_cv_run_fopen_binary],[
+  AC_RUN_IFELSE([AC_LANG_SOURCE([@%:@include <stdio.h>
+int main (int argc, char ** argv) {
+FILE * fp = fopen("conftest.@S|@ac_ext", "rb");
+return (fp == NULL) ? 1 : fclose(fp); }])],
+    [libopts_cv_run_fopen_binary=yes],[libopts_cv_run_fopen_binary=no],[libopts_cv_run_fopen_binary=no]
+  ) # end of RUN_IFELSE
+  ]) # end of AC_CACHE_VAL for libopts_cv_run_fopen_binary
+  AC_MSG_RESULT([${libopts_cv_run_fopen_binary}])
+  if test "X${libopts_cv_run_fopen_binary}" != Xno
+  then
+    AC_DEFINE([FOPEN_BINARY_FLAG],"b",
+	[fopen(3) accepts a 'b' in the mode flag])
+  else
+    AC_DEFINE([FOPEN_BINARY_FLAG],"",
+	[fopen(3) accepts a 'b' in the mode flag])
+  fi
+
+]) # end of AC_DEFUN of LIBOPTS_RUN_FOPEN_BINARY
+
+
+AC_DEFUN([LIBOPTS_RUN_FOPEN_TEXT],[
+  AC_MSG_CHECKING([whether fopen accepts "t" mode])
+  AC_CACHE_VAL([libopts_cv_run_fopen_text],[
+  AC_RUN_IFELSE([AC_LANG_SOURCE([@%:@include <stdio.h>
+int main (int argc, char ** argv) {
+FILE * fp = fopen("conftest.@S|@ac_ext", "rt");
+return (fp == NULL) ? 1 : fclose(fp); }])],
+    [libopts_cv_run_fopen_text=yes],[libopts_cv_run_fopen_text=no],[libopts_cv_run_fopen_text=no]
+  ) # end of RUN_IFELSE
+  ]) # end of AC_CACHE_VAL for libopts_cv_run_fopen_text
+  AC_MSG_RESULT([${libopts_cv_run_fopen_text}])
+  if test "X${libopts_cv_run_fopen_text}" != Xno
+  then
+    AC_DEFINE([FOPEN_TEXT_FLAG],"t",
+	[fopen(3) accepts a 't' in the mode flag])
+  else
+    AC_DEFINE([FOPEN_TEXT_FLAG],"",
+	[fopen(3) accepts a 't' in the mode flag])
+  fi
+
+]) # end of AC_DEFUN of LIBOPTS_RUN_FOPEN_TEXT
+
+
+AC_DEFUN([LIBOPTS_DISABLE_OPTIONAL_ARGS],[
+  AC_ARG_ENABLE([optional-args],
+    AS_HELP_STRING([--disable-optional-args], [not wanting optional option args]),
+    [libopts_cv_enable_optional_args=${enable_optional_args}],
+    AC_CACHE_CHECK([whether not wanting optional option args], libopts_cv_enable_optional_args,
+      libopts_cv_enable_optional_args=yes)
+  ) # end of AC_ARG_ENABLE
+  if test "X${libopts_cv_enable_optional_args}" = Xno
+  then
+    AC_DEFINE([NO_OPTIONAL_OPT_ARGS], [1],
+          [Define this if optional arguments are disallowed])
+  fi
+
+]) # end of AC_DEFUN of LIBOPTS_DISABLE_OPTIONAL_ARGS
+
+
+AC_DEFUN([INVOKE_LIBOPTS_MACROS],[
+  AC_REQUIRE([INVOKE_LIBOPTS_MACROS_FIRST])
+  # Check to see if a reg expr header is specified.
+  LIBOPTS_WITH_REGEX_HEADER
+
+  # Check to see if a working libregex can be found.
+  LIBOPTS_WITHLIB_REGEX
+
+  # Check to see if pathfind(3) works.
+  LIBOPTS_RUN_PATHFIND
+
+  # Check to see if /dev/zero is readable device.
+  LIBOPTS_TEST_DEV_ZERO
+
+  # Check to see if we have a functional realpath(3C).
+  LIBOPTS_RUN_REALPATH
+
+  # Check to see if strftime() works.
+  LIBOPTS_RUN_STRFTIME
+
+  # Check to see if fopen accepts "b" mode.
+  LIBOPTS_RUN_FOPEN_BINARY
+
+  # Check to see if fopen accepts "t" mode.
+  LIBOPTS_RUN_FOPEN_TEXT
+
+  # Check to see if not wanting optional option args.
+  LIBOPTS_DISABLE_OPTIONAL_ARGS
+
+]) # end AC_DEFUN of INVOKE_LIBOPTS_MACROS
+
+dnl @synopsis  LIBOPTS_CHECK
+dnl
+dnl If autoopts-config works, add the linking information to LIBS.
+dnl Otherwise, add ``libopts-${ao_rev}'' to SUBDIRS and run all
+dnl the config tests that the library needs.  Invoke the
+dnl "INVOKE_LIBOPTS_MACROS" macro iff we are building libopts.
+dnl
+dnl  This file is part of AutoGen.
+dnl  AutoGen Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
+dnl
+dnl  AutoGen is free software: you can redistribute it and/or modify it
+dnl  under the terms of the GNU General Public License as published by the
+dnl  Free Software Foundation, either version 3 of the License, or
+dnl  (at your option) any later version.
+dnl
+dnl  AutoGen is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+dnl  See the GNU General Public License for more details.
+dnl
+dnl  You should have received a copy of the GNU General Public License along
+dnl  with this program.  If not, see <http://www.gnu.org/licenses/>.
+dnl
+dnl Default to system libopts
+dnl
+AC_DEFUN([LIBOPTS_CHECK_COMMON],[
+  AC_REQUIRE([INVOKE_LIBOPTS_MACROS_FIRST])
+  [NEED_LIBOPTS_DIR='']
+  m4_pushdef([AO_Libopts_Dir],
+	    [ifelse($1, , [libopts], [$1])])
+  AC_ARG_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])
+       LIBOPTS_CFLAGS='-I$(top_srcdir)/AO_Libopts_Dir'
+       NEED_LIBOPTS_DIR=true
+       LIBOPTS_LDADD='$(top_builddir)/AO_Libopts_Dir/libopts.la'
+    fi])
+
+  AC_ARG_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],
+        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],
+             [lo_cv_with_autoopts_config],
+             [if autoopts-config --help 2>/dev/null 1>&2
+        then lo_cv_with_autoopts_config=autoopts-config
+        elif libopts-config --help 2>/dev/null 1>&2
+        then lo_cv_with_autoopts_config=libopts-config
+        else lo_cv_with_autoopts_config=no ; fi])
+     ) # end of AC_ARG_WITH
+
+     AC_CACHE_VAL([lo_cv_test_autoopts],[
+        if test -z "${lo_cv_with_autoopts_config}" \
+                -o X"${lo_cv_with_autoopts_config}" = Xno
+        then
+           if autoopts-config --help 2>/dev/null 1>&2
+           then lo_cv_with_autoopts_config=autoopts-config
+           elif libopts-config --help 2>/dev/null 1>&2
+           then lo_cv_with_autoopts_config=libopts-config
+           else lo_cv_with_autoopts_config=false ; fi
+        fi
+        lo_cv_test_autoopts=`
+            ${lo_cv_with_autoopts_config} --libs` 2> /dev/null
+        if test $? -ne 0 -o -z "${lo_cv_test_autoopts}"
+        then lo_cv_test_autoopts=no ; fi
+     ]) # end of CACHE_VAL
+     AC_MSG_RESULT([${lo_cv_test_autoopts}])
+
+     [if test "X${lo_cv_test_autoopts}" != Xno
+     then
+        LIBOPTS_LDADD="${lo_cv_test_autoopts}"
+        LIBOPTS_CFLAGS="`${lo_cv_with_autoopts_config} --cflags`"
+     else
+        LIBOPTS_LDADD='$(top_builddir)/]AO_Libopts_Dir[/libopts.la'
+        LIBOPTS_CFLAGS='-I$(top_srcdir)/]AO_Libopts_Dir['
+        NEED_LIBOPTS_DIR=true
+     fi
+  fi # end of if test -z "${NEED_LIBOPTS_DIR}"
+  if test -n "${LIBOPTS_BUILD_BLOCKED}" ; then
+    NEED_LIBOPTS_DIR=''
+  fi]
+  AM_CONDITIONAL([NEED_LIBOPTS], [test -n "${NEED_LIBOPTS_DIR}"])
+  AC_SUBST(LIBOPTS_LDADD)
+  AC_SUBST(LIBOPTS_CFLAGS)
+  AC_SUBST(LIBOPTS_DIR, AO_Libopts_Dir)
+  m4_popdef([AO_Libopts_Dir])
+[# end of AC_DEFUN of LIBOPTS_CHECK_COMMON]
+])
+dnl
+dnl AC_CONFIG_FILES conditionalization requires using AM_COND_IF, however
+dnl AM_COND_IF is new to Automake 1.11.  To use it on new Automake without
+dnl requiring same, a fallback implementation for older Automake is provided.
+dnl Note that disabling of AC_CONFIG_FILES requires Automake 1.11, this code
+dnl is correct only in terms of m4sh generated script.
+dnl
+m4_ifndef([AM_COND_IF],
+  [AC_DEFUN([AM_COND_IF], [
+    if test -z "$$1_TRUE"; then :
+      m4_n([$2])[]dnl
+      m4_ifval([$3],[
+    else
+      $3
+    ])dnl
+    fi[]dnl
+  ])dnl
+])
+dnl
+AC_DEFUN([LIBOPTS_CHECK_NOBUILD], [
+  m4_pushdef([AO_Libopts_Dir],
+	      [ifelse($1, , [libopts], [$1])])
+  LIBOPTS_BUILD_BLOCKED=true
+  LIBOPTS_CHECK_COMMON(AO_Libopts_Dir)
+  m4_popdef([AO_Libopts_Dir])dnl
+# end of AC_DEFUN of LIBOPTS_CHECK_NOBUILD
+])
+dnl
+AC_DEFUN([LIBOPTS_CHECK], [
+  m4_pushdef([AO_Libopts_Dir],
+	      [ifelse($1, , [libopts], [$1])])
+  LIBOPTS_BUILD_BLOCKED=''
+  LIBOPTS_CHECK_COMMON(AO_Libopts_Dir)
+  AM_COND_IF([NEED_LIBOPTS], [
+    INVOKE_LIBOPTS_MACROS
+  ])
+  AC_CONFIG_FILES(AO_Libopts_Dir/Makefile)
+  m4_popdef([AO_Libopts_Dir])dnl
+# end of AC_DEFUN of LIBOPTS_CHECK
+])

+ 41 - 0
m4/stdnoreturn.m4

@@ -0,0 +1,41 @@
+# Check for stdnoreturn.h that conforms to C11.
+
+dnl Copyright 2012-2016 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Prepare for substituting <stdnoreturn.h> if it is not supported.
+
+AC_DEFUN([gl_STDNORETURN_H],
+[
+  AC_CACHE_CHECK([for working stdnoreturn.h],
+    [gl_cv_header_working_stdnoreturn_h],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <stdlib.h>
+            #include <stdnoreturn.h>
+            /* Do not check for 'noreturn' after the return type.
+               C11 allows it, but it's rarely done that way
+               and circa-2012 bleeding-edge GCC rejects it when given
+               -Werror=old-style-declaration.  */
+            noreturn void foo1 (void) { exit (0); }
+            _Noreturn void foo2 (void) { exit (0); }
+            int testit (int argc, char **argv) {
+              if (argc & 1)
+                return 0;
+              (argv[0][0] ? foo1 : foo2) ();
+            }
+          ]])],
+       [gl_cv_header_working_stdnoreturn_h=yes],
+       [gl_cv_header_working_stdnoreturn_h=no])])
+
+  if test $gl_cv_header_working_stdnoreturn_h = yes; then
+    STDNORETURN_H=''
+  else
+    STDNORETURN_H='stdnoreturn.h'
+  fi
+
+  AC_SUBST([STDNORETURN_H])
+  AM_CONDITIONAL([GL_GENERATE_STDNORETURN_H], [test -n "$STDNORETURN_H"])
+])

+ 6 - 3
scripts/Makefile.in

@@ -90,9 +90,12 @@ host_triplet = @host@
 target_triplet = @target@
 subdir = scripts
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/libopts/m4/libopts.m4 \
-	$(top_srcdir)/libopts/m4/stdnoreturn.m4 \
-	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/m4/libopts.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/stdnoreturn.m4 $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)

+ 6 - 3
src/Makefile.in

@@ -99,9 +99,12 @@ bin_PROGRAMS = tcpreplay$(EXEEXT) tcpprep$(EXEEXT) tcprewrite$(EXEEXT) \
 @COMPILE_TCPLIVEPLAY_TRUE@am__append_4 = tcpliveplay.1
 subdir = src
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/libopts/m4/libopts.m4 \
-	$(top_srcdir)/libopts/m4/stdnoreturn.m4 \
-	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/m4/libopts.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/stdnoreturn.m4 $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \

+ 1 - 1
src/bridge.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 1 - 1
src/bridge.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 1 - 1
src/common.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 6 - 3
src/common/Makefile.in

@@ -94,9 +94,12 @@ target_triplet = @target@
 @COMPILE_NETMAP_TRUE@am__append_2 = netmap.c
 subdir = src/common
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/libopts/m4/libopts.m4 \
-	$(top_srcdir)/libopts/m4/stdnoreturn.m4 \
-	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/m4/libopts.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/stdnoreturn.m4 $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \

+ 1 - 1
src/common/cache.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 1 - 1
src/common/cache.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 5 - 7
src/common/cidr.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 
@@ -110,20 +110,18 @@ u_char *
 ip2cidr(const unsigned long ip, const int masklen)
 {
     u_char *network;
-    char mask[3];
+    char mask[32];
 
     network = (u_char *)safe_malloc(20);
 
     strlcpy((char *)network, (char *)get_addr2name4(ip, RESOLVE), 20);
 
     strcat((char *)network, "/");
-    if (masklen < 10) {
-        snprintf(mask, sizeof(mask), "%d", masklen);
+    snprintf(mask, sizeof(mask), "%d", masklen);
+    if (masklen < 10)
         strncat((char *)network, mask, 1);
-    } else {
-        snprintf(mask, sizeof(mask), "%d", masklen);
+    else
         strncat((char *)network, mask, 2);
-    }
 
     return (network);
 }

+ 1 - 1
src/common/cidr.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 1 - 1
src/common/err.c

@@ -7,7 +7,7 @@
  *
  * Copyright (c) 2001-2010 Aaron Turner.
  *
- * Copyright (c) 2013-2018 Fred Klassen - AppNeta
+ * Copyright (c) 2013-2022 Fred Klassen - AppNeta
  *
  * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
  *

+ 1 - 1
src/common/err.h

@@ -7,7 +7,7 @@
  *
  * Copyright (c) 2001-2010 Aaron Turner.
  *
- * Copyright (c) 2013-2018 Fred Klassen - AppNeta
+ * Copyright (c) 2013-2022 Fred Klassen - AppNeta
  *
  * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
  *

+ 1 - 1
src/common/fakepcap.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 1 - 1
src/common/fakepcap.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 1 - 1
src/common/fakepcapnav.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 1 - 1
src/common/fakepcapnav.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 35 - 92
src/common/flows.c

@@ -1,6 +1,6 @@
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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,6 +23,10 @@
 #include <string.h>
 #include "../../lib/sll.h"
 
+#define JUNIPER_FLAG_NO_L2          0x02     /* L2 header */
+#define JUNIPER_FLAG_EXT            0x80     /* Juniper extensions present */
+#define JUNIPER_PCAP_MAGIC          "MGC"
+
 /* 5-tuple plus VLAN ID */
 typedef struct flow_entry_data {
     union {
@@ -157,23 +161,25 @@ static inline flow_entry_type_t hash_put_data(flow_hash_table_t *fht, const uint
 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)
 {
+    uint32_t pkt_len = pkthdr->caplen;
+    const u_char *packet = pktdata;
+    uint32_t _U_ vlan_offset;
+    uint32_t _U_ l2offset;
     uint16_t ether_type = 0;
     ipv4_hdr_t *ip_hdr = NULL;
     ipv6_hdr_t *ip6_hdr = NULL;
     tcp_hdr_t *tcp_hdr;
     udp_hdr_t *udp_hdr;
     icmpv4_hdr_t *icmp_hdr;
-    hdlc_hdr_t *hdlc_hdr;
-    sll_hdr_t *sll_hdr;
-    struct tcpr_pppserial_hdr *ppp;
     flow_entry_data_t entry;
-    uint32_t l2_len = 0;
-    int ip_len;
+    uint32_t l2len = 0;
     uint8_t protocol;
     uint32_t hash;
+    int ip_len;
+    int res;
 
     assert(fht);
-    assert(pktdata);
+    assert(packet);
 
     /*
      * extract the 5-tuple and populate the entry data
@@ -181,90 +187,27 @@ flow_entry_type_t flow_decode(flow_hash_table_t *fht, const struct pcap_pkthdr *
 
     memset(&entry, 0, sizeof(entry));
 
-    switch (datalink) {
-    case DLT_LINUX_SLL:
-        l2_len = 16;
-        if (pkthdr->caplen < l2_len)
-            return FLOW_ENTRY_INVALID;
-
-        sll_hdr = (sll_hdr_t *)pktdata;
-        ether_type = sll_hdr->sll_protocol;
-        break;
-
-    case DLT_PPP_SERIAL:
-        l2_len = 4;
-        if (pkthdr->caplen < l2_len)
-            return FLOW_ENTRY_INVALID;
-
-        ppp = (struct tcpr_pppserial_hdr *)pktdata;
-        if (ntohs(ppp->protocol) == 0x0021)
-            ether_type = htons(ETHERTYPE_IP);
-        else
-            ether_type = ppp->protocol;
-        break;
-
-    case DLT_C_HDLC:
-        l2_len = 4;
-        if (pkthdr->caplen < l2_len)
-            return FLOW_ENTRY_INVALID;
-
-        hdlc_hdr = (hdlc_hdr_t *)pktdata;
-        ether_type = hdlc_hdr->protocol;
-        break;
-
-    case DLT_RAW:
-        if ((pktdata[0] >> 4) == 4)
-            ether_type = ETHERTYPE_IP;
-        else if ((pktdata[0] >> 4) == 6)
-            ether_type = ETHERTYPE_IP6;
-        break;
-
-    case DLT_JUNIPER_ETHER:
-        if (pkthdr->caplen < 5)
-            return FLOW_ENTRY_INVALID;
-
-        if (memcmp(pktdata, "MGC", 3))
-            warnx("No Magic Number found: %s (0x%x)",
-                 pcap_datalink_val_to_description(datalink), datalink);
-
-        if ((pktdata[3] & 0x80) == 0x80) {
-            l2_len = ntohs(*((uint16_t*)&pktdata[4]));
-            l2_len += 6;
-        } else {
-            l2_len = 4; /* no header extensions */
-        }
+    res = get_l2len_protocol(packet,
+                             pkt_len,
+                             datalink,
+                             &ether_type,
+                             &l2len,
+                             &l2offset,
+                             &vlan_offset);
 
-        /* fallthrough */
-    case DLT_EN10MB:
-        /* l2_len will be zero if we did not fall through */
-        if (pkthdr->caplen < l2_len + sizeof(eth_hdr_t))
-            return FLOW_ENTRY_INVALID;
-
-        ether_type = ntohs(((eth_hdr_t*)(pktdata + l2_len))->ether_type);
-        l2_len += sizeof(eth_hdr_t);
-
-        while (ether_type == ETHERTYPE_VLAN) {
-            if (pkthdr->caplen < l2_len + sizeof(vlan_hdr_t))
-                    return FLOW_ENTRY_INVALID;
-
-            vlan_hdr_t *vlan_hdr = (vlan_hdr_t *)(pktdata + l2_len);
-            entry.vlan = vlan_hdr->vlan_tci & htons(0xfff);
-            ether_type = ntohs(vlan_hdr->vlan_tpid);
-            l2_len += 4;
-        }
-        break;
-
-    default:
+    if (res == -1) {
         warnx("Unable to process unsupported DLT type: %s (0x%x)",
-             pcap_datalink_val_to_description(datalink), datalink);
+              pcap_datalink_val_to_description(datalink), datalink);
         return FLOW_ENTRY_INVALID;
     }
 
+    assert(l2len > 0);
+
     if (ether_type == ETHERTYPE_IP) {
-        if (pkthdr->caplen < l2_len + sizeof(ipv4_hdr_t))
+        if (pkt_len < l2len + sizeof(ipv4_hdr_t))
                 return FLOW_ENTRY_INVALID;
 
-        ip_hdr = (ipv4_hdr_t *)(pktdata + l2_len);
+        ip_hdr = (ipv4_hdr_t *)(packet + l2len);
 
         if (ip_hdr->ip_v != 4)
             return FLOW_ENTRY_NON_IP;
@@ -274,13 +217,13 @@ flow_entry_type_t flow_decode(flow_hash_table_t *fht, const struct pcap_pkthdr *
         entry.src_ip.in = ip_hdr->ip_src;
         entry.dst_ip.in = ip_hdr->ip_dst;
     } else if (ether_type == ETHERTYPE_IP6) {
-        if (pkthdr->caplen < l2_len + sizeof(ipv6_hdr_t))
+        if (pkt_len < l2len + sizeof(ipv6_hdr_t))
                 return FLOW_ENTRY_INVALID;
 
-        if ((pktdata[0] >> 4) != 6)
+        if ((packet[0] >> 4) != 6)
             return FLOW_ENTRY_NON_IP;
 
-        ip6_hdr = (ipv6_hdr_t *)(pktdata + l2_len);
+        ip6_hdr = (ipv6_hdr_t *)(packet + l2len);
         ip_len = sizeof(*ip6_hdr);
         protocol = ip6_hdr->ip_nh;
 
@@ -299,26 +242,26 @@ flow_entry_type_t flow_decode(flow_hash_table_t *fht, const struct pcap_pkthdr *
 
     switch (protocol) {
     case IPPROTO_UDP:
-        if (pkthdr->caplen < (l2_len + ip_len + sizeof(udp_hdr_t)))
+        if (pkt_len < (l2len + ip_len + sizeof(udp_hdr_t)))
             return FLOW_ENTRY_INVALID;
-        udp_hdr = (udp_hdr_t*)(pktdata + ip_len + l2_len);
+        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 (pkthdr->caplen < (l2_len + ip_len + sizeof(tcp_hdr_t)))
+        if (pkt_len < (l2len + ip_len + sizeof(tcp_hdr_t)))
             return FLOW_ENTRY_INVALID;
-        tcp_hdr = (tcp_hdr_t*)(pktdata + ip_len + l2_len);
+        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 (pkthdr->caplen < (l2_len + ip_len + sizeof(icmpv4_hdr_t)))
+        if (pkt_len < (l2len + ip_len + sizeof(icmpv4_hdr_t)))
             return FLOW_ENTRY_INVALID;
-        icmp_hdr = (icmpv4_hdr_t*)(pktdata + ip_len + l2_len);
+        icmp_hdr = (icmpv4_hdr_t*)(packet + ip_len + l2len);
         entry.src_port = icmp_hdr->icmp_type;
         entry.dst_port = icmp_hdr->icmp_code;
         break;

+ 1 - 1
src/common/flows.h

@@ -1,6 +1,6 @@
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 348 - 212
src/common/get.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 
@@ -71,111 +71,318 @@ get_pcap_version(void)
 #endif
 }
 
+/*
+ * Advance L2 protocol and L2 length past any MPLS labels.
+ * e.g. https://www.cloudshark.org/captures/20f210391b21
+ *
+ * If EoMPLS is detected, also advance L2 offset to point to the
+ * encapsulated L2.
+ * e.g. https://www.cloudshark.org/captures/b15412060b3d
+ *
+ * pktdata:       pointer to the raw packet
+ * datalen:       number of bytes captured in the packet
+ * next_protocol: reference to the next L2 protocol to be examined and possibly updated
+ * l2len:         reference to the length of the L2 header discovered so far
+ * l2offset:      reference to the offset to the start of the L2 header - typically 0
+ *
+ * return 0 on success, -1 on failure
+ */
+int parse_mpls(const u_char *pktdata,
+               const uint32_t datalen,
+               uint16_t *next_protocol,
+               uint32_t *l2len,
+               uint32_t *l2offset)
+{
+    struct tcpr_mpls_label *mpls_label;
+    int len_remaining = (int)datalen;
+    u_char first_nibble;
+    eth_hdr_t *eth_hdr;
+    bool bos = false;
+    uint32_t label;
+    int len;
+
+    assert(next_protocol);
+    assert(l2len);
+    assert(l2offset);
+
+    len = (int)*l2len;
+
+    /* move over MPLS labels until we get to the last one */
+    while (!bos) {
+        if (len_remaining < (int)sizeof(*mpls_label))
+            return -1;
+
+        mpls_label = (struct tcpr_mpls_label*)(pktdata + len);
+        len += sizeof(*mpls_label);
+        len_remaining -= sizeof(*mpls_label);
+        bos = (ntohl(mpls_label->entry) & MPLS_LS_S_MASK) != 0;
+        label = ntohl(mpls_label->entry) >> MPLS_LS_LABEL_SHIFT;
+        if (label == MPLS_LABEL_GACH) {
+            /* Generic Associated Channel Header */
+            warn("GACH MPLS label not supported at this time");
+            return -1;
+        }
+    }
 
+    if (len_remaining < 4)
+        return -1;
 
-/**
- * returns the L2 protocol (IP, ARP, etc)
- * or 0 for error
+    first_nibble = *((u_char *)(mpls_label + 1)) >> 4;
+    switch(first_nibble) {
+    case 4:
+        *next_protocol = ETHERTYPE_IP;
+        break;
+    case 6:
+        *next_protocol = ETHERTYPE_IP6;
+        break;
+    case 0:
+        /* EoMPLS - jump over PW Ethernet Control Word and handle
+         * inner Ethernet header
+         */
+        len += 4;
+        len_remaining -= 4;
+        if (len_remaining < (int)sizeof(*eth_hdr))
+            return -1;
+
+        *l2offset = len;
+        eth_hdr = (eth_hdr_t*)(pktdata + len);
+        len += sizeof(*eth_hdr);
+        *next_protocol = ntohs(eth_hdr->ether_type);
+        break;
+    default:
+        /* suspect Generic Associated Channel Header */
+        return -1;
+    }
+
+    *l2len = (uint32_t)len;
+    return 0;
+}
+
+/*
+ * Advance L2 protocol and L2 length past any VLAN tags.
+ * e.g. https://www.cloudshark.org/captures/e4fa464563d2
+ *
+ * pktdata:       pointer to the raw packet
+ * datalen:       number of bytes captured in the packet
+ * next_protocol: reference to the next L2 protocol to be examined and possibly updated
+ * l2len:         reference to the length of the L2 header discovered so far
+ *
+ * return 0 on success, -1 on failure
+ */
+int parse_vlan(const u_char *pktdata,
+               const uint32_t datalen,
+               uint16_t *next_protocol,
+               uint32_t *l2len)
+{
+    vlan_hdr_t *vlan_hdr;
+    if ((size_t)datalen < *l2len + sizeof(*vlan_hdr))
+        return -1;
+
+    vlan_hdr = (vlan_hdr_t*)(pktdata + *l2len);
+    *next_protocol = ntohs(vlan_hdr->vlan_tpid);
+    *l2len += sizeof(vlan_hdr_t);
+
+    return 0;
+}
+
+/*
+ * Loop through all non-protocol L2 headers while updating key variables
+ *
+ * pktdata:       pointer to the raw packet
+ * datalen:       number of bytes captured in the packet
+ * next_protocol: reference to the next L2 protocol to be examined and possibly updated
+ * l2len:         reference to the length of the L2 header discovered so far
+ * l2offset:      reference to the offset to the start of the L2 header - typically 0
+ * vlan_offset: reference to the offset to the start of the VLAN headers, if any
+ *
+ * return 0 on success, -1 on failure
+ */
+static int parse_metadata(const u_char *pktdata,
+                          const uint32_t datalen,
+                          uint16_t *next_protocol,
+                          uint32_t *l2len,
+                          uint32_t *l2offset,
+                          uint32_t *vlan_offset)
+{
+    bool done = false;
+    int res = 0;
+    while (!done && res == 0) {
+        switch (*next_protocol) {
+        case ETHERTYPE_VLAN:
+        case ETHERTYPE_Q_IN_Q:
+        case ETHERTYPE_8021QINQ:
+            if (*vlan_offset == 0)
+                *vlan_offset = *l2len;
+
+            res = parse_vlan(pktdata, datalen, next_protocol, l2len);
+            break;
+        case ETHERTYPE_MPLS:
+        case ETHERTYPE_MPLS_MULTI:
+            res = parse_mpls(pktdata, datalen, next_protocol, l2len, l2offset);
+            break;
+        default:
+            done = true;
+        }
+    }
+
+    return res;
+}
+
+/*
+ * Parse raw packet and get the L3 protocol and L2 length. In cases where the
+ * L2 header is not at the beginning of the packet
+ * (e.g. DLT_JUNIPER_ETHER or EoMPLS), report the offset to the start of the
+ * L2 header
+ *
+ * pktdata:     pointer to the raw packet
+ * datalen:     number of bytes captured in the packet
+ * datalink:    data link type of the packet
+ * protocol:    reference to the L3 protocol as discovered in the L2 header
+ * l2len:       reference to the total length of the L2 header
+ * l2offset:    reference to the offset to the start of the L2 header (typically 0)
+ * vlan_offset: reference to the offset to the start of the VLAN headers, if any
+ *
+ * return 0 on success, -1 on failure
  */
-uint16_t
-get_l2protocol(const u_char *pktdata, const uint32_t datalen, const int datalink)
+int get_l2len_protocol(const u_char *pktdata,
+                       const uint32_t datalen,
+                       const int datalink,
+                       uint16_t *protocol,
+                       uint32_t *l2len,
+                       uint32_t *l2offset,
+                       uint32_t *vlan_offset)
 {
-    uint16_t eth_hdr_offset = 0;
+    assert(protocol);
+    assert(l2len);
+    assert(l2offset);
+    assert(vlan_offset);
 
     if (!pktdata || !datalen) {
-        errx(-1, "invalid l2 parameters: pktdata=0x%p len=%d",
-                pktdata, datalen);
-        return 0;
+        errx(-1, "get_l2len_protocol: invalid L2 parameters: pktdata=0x%p len=%d",
+             pktdata,
+             datalen);
+        return -1;
     }
 
+    *protocol = 0;
+    *l2len = 0;
+    *l2offset = 0;
+    *vlan_offset = 0;
+
     switch (datalink) {
     case DLT_RAW:
-        if (datalen < 1)
-            return 0;
+        if (datalen == 0)
+            return -1;
+
         if ((pktdata[0] >> 4) == 4)
-            return ETHERTYPE_IP;
+            *protocol = ETHERTYPE_IP;
         else if ((pktdata[0] >> 4) == 6)
-            return ETHERTYPE_IP6;
+            *protocol = ETHERTYPE_IP6;
         break;
-
     case DLT_JUNIPER_ETHER:
         if (datalen < 4)
-            return 0;
+            return -1;
 
         if (memcmp(pktdata, JUNIPER_PCAP_MAGIC, 3)) {
             warnx("No Magic Number found during protocol lookup: %s (0x%x)",
-                 pcap_datalink_val_to_description(datalink), datalink);
-            return 0;
+                  pcap_datalink_val_to_description(datalink),
+                  datalink);
+            return -1;
         }
 
         if ((pktdata[3] & JUNIPER_FLAG_EXT) == JUNIPER_FLAG_EXT) {
             if (datalen < 6)
-                return 0;  /* datalen too short */
+                return -1;
 
-            eth_hdr_offset = ntohs(*((uint16_t*)&pktdata[4]));
-            eth_hdr_offset += 6; /* MGC + flags + ext_total_len */
+            *l2offset = ntohs(*((uint16_t*)&pktdata[4]));
+            *l2offset += 6; /* MGC + flags + ext_total_len */
         } else {
-            eth_hdr_offset = 4; /* MGC + flags (no header extensions) */
+            *l2offset = 4; /* MGC + flags (no header extensions) */
         }
+
         if ((pktdata[3] & JUNIPER_FLAG_NO_L2) == JUNIPER_FLAG_NO_L2) {
-             /* no L2 header present - eth_hdr_offset is actually IP offset */
-            uint32_t ip_hdr_offset = eth_hdr_offset;
+            /* no L2 header present - *l2offset is actually IP offset */
+            uint32_t ip_hdr_offset = *l2offset;
             if (datalen < ip_hdr_offset + 1)
-                return 0;
+                return -1;
+
             if ((pktdata[ip_hdr_offset] >> 4) == 4)
-                return ETHERTYPE_IP;
+                *protocol = ETHERTYPE_IP;
             else if ((pktdata[ip_hdr_offset] >> 4) == 6)
-                return ETHERTYPE_IP6;
-            else
-                return 0;
-        }
-        /* fall through */
-    case DLT_EN10MB:
-        if ((size_t)datalen >= (sizeof(eth_hdr_t) + eth_hdr_offset)) {
-            eth_hdr_t *eth_hdr = (eth_hdr_t *)(pktdata + eth_hdr_offset);
-            uint16_t ether_type = ntohs(eth_hdr->ether_type);
-            uint16_t l2_len = sizeof(*eth_hdr) + eth_hdr_offset;
-            while (ether_type == ETHERTYPE_VLAN) {
-                if (datalen < l2_len + sizeof(vlan_hdr_t))
-                     return 0;
-
-                 vlan_hdr_t *vlan_hdr = (vlan_hdr_t*)(pktdata + l2_len);
-                 ether_type = ntohs(vlan_hdr->vlan_tpid);
-                 l2_len += sizeof(vlan_hdr_t);
-            }
+                *protocol = ETHERTYPE_IP6;
 
-            return ether_type; /* yes, return it in host byte order */
+            return 0;
         }
-        break;
 
-    case DLT_PPP_SERIAL:
-        if ((size_t)datalen >= sizeof(struct tcpr_pppserial_hdr)) {
-            struct tcpr_pppserial_hdr *ppp = (struct tcpr_pppserial_hdr *)pktdata;
-            if (ntohs(ppp->protocol) == 0x0021)
-                return htons(ETHERTYPE_IP);
+        /* fall through */
+    case DLT_EN10MB:
+    {
+        eth_hdr_t *eth_hdr = (eth_hdr_t*)(pktdata + *l2offset);
+        uint32_t l2_net_off = sizeof(*eth_hdr) + *l2offset;
+        uint16_t ether_type = ntohs(eth_hdr->ether_type);
+
+        if (datalen <= l2_net_off)
+            return -1;
+
+        if (parse_metadata(pktdata,
+                           datalen,
+                           &ether_type,
+                           &l2_net_off,
+                           l2offset,
+                           vlan_offset))
+            return -1;
+
+        if (datalen < l2_net_off)
+            return -1;
+
+        *l2len = l2_net_off;
+        if (ether_type > 1500) {
+            /* Ethernet II frame - return in host order */
+            *protocol = ether_type;
+        } 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
-                return ppp->protocol;
+                /* unsupported 802.3 protocol */
+                return -1;
         }
         break;
+    }
+    case DLT_PPP_SERIAL:
+        if ((size_t)datalen < sizeof(struct tcpr_pppserial_hdr))
+            return -1;
+
+        struct tcpr_pppserial_hdr *ppp = (struct tcpr_pppserial_hdr*)pktdata;
+        *l2len = sizeof(*ppp);
+        if (ntohs(ppp->protocol) == 0x0021)
+            *protocol = ETHERTYPE_IP;
+        else
+            *protocol = ntohs(ppp->protocol);
 
-    case DLT_C_HDLC:
-        if ((size_t)datalen >= sizeof(hdlc_hdr_t)) {
-            hdlc_hdr_t *hdlc_hdr = (hdlc_hdr_t *)pktdata;
-            return hdlc_hdr->protocol;
-        }
         break;
+    case DLT_C_HDLC:
+        if (datalen < CISCO_HDLC_LEN)
+            return -1;
 
-    case DLT_LINUX_SLL:
-        if ((size_t)datalen >= sizeof(sll_hdr_t)) {
-            sll_hdr_t *sll_hdr = (sll_hdr_t *)pktdata;
-            return sll_hdr->sll_protocol;
-        }
+        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)
+            return -1;
 
+        sll_hdr_t *sll_hdr = (sll_hdr_t*)pktdata;
+        *l2len = sizeof(*sll_hdr);
+        *protocol = ntohs(sll_hdr->sll_protocol);
+        break;
     default:
-        errx(-1, "Unable to process unsupported DLT type: %s (0x%x)", 
-             pcap_datalink_val_to_description(datalink), datalink);
-
+        errx(-1, "Unable to process unsupported DLT type: %s (0x%x)",
+             pcap_datalink_val_to_description(datalink),
+             datalink);
     }
 
     return 0;
@@ -187,93 +394,23 @@ get_l2protocol(const u_char *pktdata, const uint32_t datalen, const int datalink
 int
 get_l2len(const u_char *pktdata, const int datalen, const int datalink)
 {
-    int l2_len = 0;
-
-    assert(pktdata);
-    assert(datalen);
-
-    switch (datalink) {
-    case DLT_RAW:
-        /* pktdata IS the ip header! */
-        break;
-
-    case DLT_JUNIPER_ETHER:
-        if (datalen < 4) {
-            l2_len = -1;
-            break;
-        }
-
-        if (memcmp(pktdata, JUNIPER_PCAP_MAGIC, 3)) {
-            warnx("No Magic Number found during L2 lookup: %s (0x%x)",
-                  pcap_datalink_val_to_description(datalink), datalink);
-            l2_len = -1;
-            break;
-        }
-
-        if ((pktdata[3] & JUNIPER_FLAG_NO_L2) == JUNIPER_FLAG_NO_L2) {
-            /* no L2 header present */
-            l2_len = 0;
-            break;
-        }
-
-        if ((pktdata[3] & JUNIPER_FLAG_EXT) == JUNIPER_FLAG_EXT) {
-            if (datalen < 6) {
-                /* datalen too short */
-                l2_len = -1;
-                break;
-            }
-            l2_len = ntohs(*((uint16_t*)&pktdata[4]));
-            l2_len += 6;        /* MGC + flags + ext_total_len */
-        } else {
-            l2_len = 4;         /* MGC + flags */
-        }
-        /* fall through */
-    case DLT_EN10MB:
-        if ((size_t)datalen >= sizeof(eth_hdr_t) + l2_len) {
-            uint16_t ether_type = ntohs(((eth_hdr_t*)(pktdata + l2_len))->ether_type);
-
-            l2_len += sizeof(eth_hdr_t);
-            while (ether_type == ETHERTYPE_VLAN) {
-                if ((size_t)datalen < sizeof(vlan_hdr_t) + l2_len) {
-                    l2_len = -1;
-                    break;
-                }
-                vlan_hdr_t *vlan_hdr = (vlan_hdr_t *)(pktdata + l2_len);
-                ether_type = ntohs(vlan_hdr->vlan_tpid);
-                l2_len += 4;
-            }
-        }
-
-        if (datalen < l2_len)
-            l2_len = -1;
-
-        break;
-
-    case DLT_PPP_SERIAL:
-        if (datalen >= 4) {
-            l2_len = 4;
-        }
-        break;
-
-    case DLT_C_HDLC:
-        if (datalen >= CISCO_HDLC_LEN) {
-            l2_len = CISCO_HDLC_LEN;
-        }
-        break;
-
-    case DLT_LINUX_SLL:
-        if (datalen >= SLL_HDR_LEN) {
-            l2_len = SLL_HDR_LEN;
-        }
-        break;
-
-    default:
-        errx(-1, "Unable to process unsupported DLT type: %s (0x%x)", 
-             pcap_datalink_val_to_description(datalink), datalink);
-        return -1; /* we shouldn't get here */
-    }
+    uint16_t _U_ protocol;
+    uint32_t _U_ l2offset;
+    uint32_t _U_ vlan_offset;
+    uint32_t l2len = 0;
+
+    int res = get_l2len_protocol(pktdata,
+                                 datalen,
+                                 datalink,
+                                 &protocol,
+                                 &l2len,
+                                 &l2offset,
+                                 &vlan_offset);
+
+    if (res == -1)
+        return 0;
 
-    return l2_len;
+    return l2len;
 }
 
 /**
@@ -289,50 +426,45 @@ get_l2len(const u_char *pktdata, const int datalen, const int datalink)
 const u_char *
 get_ipv4(const u_char *pktdata, int datalen, int datalink, u_char **newbuff)
 {
+    const u_char *packet = pktdata;
     const u_char *ip_hdr = NULL;
-    int l2_len = 0;
+    ssize_t pkt_len = datalen;
+    uint32_t _U_ vlan_offset;
+    uint32_t l2offset;
     uint16_t proto;
+    uint32_t l2len;
+    int res;
 
-    assert(pktdata);
-    assert(datalen);
+    assert(packet);
+    assert(pkt_len);
     assert(*newbuff);
 
-    l2_len = get_l2len(pktdata, datalen, datalink);
+    res = get_l2len_protocol(packet,
+                             pkt_len,
+                             datalink,
+                             &proto,
+                             &l2len,
+                             &l2offset,
+                             &vlan_offset);
 
-    /* sanity... datalen must be > l2_len + IP header len*/
-    if (l2_len < 0 || l2_len + TCPR_IPV4_H > datalen) {
+    /* sanity... pkt_len must be > l2len + IP header len*/
+    if (res == -1 || l2len + TCPR_IPV4_H > pkt_len) {
         dbg(1, "get_ipv4(): Layer 2 len > total packet len, hence no IP header");
         return NULL;
     }
 
-    proto = get_l2protocol(pktdata, datalen, datalink);
-
     if (proto != ETHERTYPE_IP)
         return NULL;
 
-#ifdef FORCE_ALIGN
-    /*
-     * copy layer 3 and up to our temp packet buffer
-     * for now on, we have to edit the packetbuff because
-     * just before we send the packet, we copy the packetbuff 
-     * back onto the pkt.data + l2len buffer
-     * we do all this work to prevent byte alignment issues
-     */
-    if (l2_len % sizeof(long)) {
-        memcpy(*newbuff, (pktdata + l2_len), (datalen - l2_len));
-        ip_hdr = *newbuff;
-    } else {
+    packet += l2offset;
+    l2len -= l2offset;
+    pkt_len -= l2offset;
 
-        /* we don't have to do a memcpy if l2_len lands on a boundary */
-        ip_hdr = (pktdata + l2_len);
-    }
-#else
     /*
      * on non-strict byte align systems, don't need to memcpy(), 
      * just point to l2len bytes into the existing buffer
      */
-    ip_hdr = (pktdata + l2_len);
-#endif
+    ip_hdr = (packet + l2len);
 
     return ip_hdr;
 }
@@ -351,50 +483,45 @@ get_ipv4(const u_char *pktdata, int datalen, int datalink, u_char **newbuff)
 const u_char *
 get_ipv6(const u_char *pktdata, int datalen, int datalink, u_char **newbuff)
 {
+    const u_char *packet = pktdata;
     const u_char *ip6_hdr = NULL;
-    int l2_len = 0;
+    ssize_t pkt_len = datalen;
+    uint32_t _U_ vlan_offset;
+    uint32_t l2offset;
     uint16_t proto;
+    uint32_t l2len;
+    int res;
 
-    assert(pktdata);
-    assert(datalen);
+    assert(packet);
+    assert(pkt_len);
     assert(*newbuff);
 
-    l2_len = get_l2len(pktdata, datalen, datalink);
+    res = get_l2len_protocol(packet,
+                             pkt_len,
+                             datalink,
+                             &proto,
+                             &l2len,
+                             &l2offset,
+                             &vlan_offset);
 
-    /* sanity... datalen must be > l2_len + IP header len*/
-    if (l2_len < 0 || l2_len + TCPR_IPV6_H > datalen) {
+    /* sanity... pkt_len must be > l2len + IP header len*/
+    if (res == -1 || l2len + TCPR_IPV6_H > pkt_len) {
         dbg(1, "get_ipv6(): Layer 2 len > total packet len, hence no IPv6 header");
         return NULL;
     }
 
-    proto = get_l2protocol(pktdata, datalen, datalink);
-
     if (proto != ETHERTYPE_IP6)
         return NULL;
 
-#ifdef FORCE_ALIGN
-    /*
-     * copy layer 3 and up to our temp packet buffer
-     * for now on, we have to edit the packetbuff because
-     * just before we send the packet, we copy the packetbuff
-     * back onto the pkt.data + l2len buffer
-     * we do all this work to prevent byte alignment issues
-     */
-    if (l2_len % sizeof(long)) {
-        memcpy(*newbuff, (pktdata + l2_len), (datalen - l2_len));
-        ip6_hdr = *newbuff;
-    } else {
+    packet += l2offset;
+    l2len -= l2offset;
+    pkt_len -= l2offset;
 
-        /* we don't have to do a memcpy if l2_len lands on a boundary */
-        ip6_hdr = (pktdata + l2_len);
-    }
-#else
     /*
      * on non-strict byte align systems, don't need to memcpy(),
      * just point to l2len bytes into the existing buffer
      */
-    ip6_hdr = (pktdata + l2_len);
-#endif
+    ip6_hdr = (packet + l2len);
 
     return ip6_hdr;
 }
@@ -428,8 +555,9 @@ void *
 get_layer4_v6(const ipv6_hdr_t *ip6_hdr, const int l3len)
 {
     struct tcpr_ipv6_ext_hdr_base *next, *exthdr;
-    uint8_t proto;
+    bool done = false;
     uint32_t maxlen;
+    uint8_t proto;
     int min_len;
 
     assert(ip6_hdr);
@@ -442,14 +570,14 @@ get_layer4_v6(const ipv6_hdr_t *ip6_hdr, const int l3len)
     next = (struct tcpr_ipv6_ext_hdr_base *)((u_char *)ip6_hdr + TCPR_IPV6_H);
     proto = ip6_hdr->ip_nh;
 
-    while (1) {
+    while (!done) {
         dbgx(3, "Processing proto: 0x%hx", (uint16_t)proto);
 
         switch (proto) {
         /* recurse due to v6-in-v6, need to recast next as an IPv6 Header */
         case TCPR_IPV6_NH_IPV6:
             dbg(3, "recursing due to v6-in-v6");
-            return get_layer4_v6((ipv6_hdr_t *)next, l3len - min_len);
+            next = get_layer4_v6((ipv6_hdr_t *)next, l3len - min_len);
             break;
 
         /* loop again */
@@ -460,8 +588,10 @@ get_layer4_v6(const ipv6_hdr_t *ip6_hdr, const int l3len)
             dbgx(3, "Going deeper due to extension header 0x%02X", proto);
             maxlen = l3len - (int)((u_char *)ip6_hdr - (u_char *)next);
             exthdr = get_ipv6_next(next, maxlen);
-            if (exthdr == NULL)
-                return next;
+            if (exthdr == NULL) {
+                done = true;
+                break;
+            }
             proto = exthdr->ip_nh;
             next = exthdr;
             break;
@@ -471,7 +601,8 @@ get_layer4_v6(const ipv6_hdr_t *ip6_hdr, const int l3len)
          */
         case TCPR_IPV6_NH_FRAGMENT:
         case TCPR_IPV6_NH_ESP:
-            return NULL;
+            next = NULL;
+            done = true;
             break;
 
         /*
@@ -481,14 +612,19 @@ get_layer4_v6(const ipv6_hdr_t *ip6_hdr, const int l3len)
             if (proto != ip6_hdr->ip_nh) {
                 dbgx(3, "Returning byte offset of this ext header: %u", 
                         IPV6_EXTLEN_TO_BYTES(next->ip_len));
-                return (void *)((u_char *)next + IPV6_EXTLEN_TO_BYTES(next->ip_len));
+                next =  (void *)((u_char *)next + IPV6_EXTLEN_TO_BYTES(next->ip_len));
             } else {
                 dbgx(3, "%s", "Returning end of IPv6 Header");
-                return next;
             }
-            break;
+
+            done = true;
         } /* switch */
     } /* while */
+
+    if (!next || (u_char*)next > (u_char*)ip6_hdr + l3len)
+        return NULL;
+
+    return next;
 }
 
 

+ 19 - 2
src/common/get.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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,9 +26,26 @@
 #include "common.h"
 
 
+int parse_mpls(const u_char *pktdata,
+               const uint32_t datalen,
+               uint16_t *protocol,
+               uint32_t *l2len,
+               uint32_t *l2offset);
+
+int parse_vlan(const u_char *pktdata,
+               const uint32_t datalen,
+               uint16_t *next_protocol,
+               uint32_t *l2len);
+
 int get_l2len(const u_char *pktdata, const int datalen, const int datalink);
 
-u_int16_t get_l2protocol(const u_char *pktdata, const uint32_t datalen, const int datalink);
+int get_l2len_protocol(const u_char *pktdata,
+                       const uint32_t datalen,
+                       const int datalink,
+                       uint16_t *protocol,
+                       uint32_t *l2len,
+                       uint32_t *l2offset,
+                       uint32_t *vlan_offset);
 
 void *get_layer4_v4(const ipv4_hdr_t *ip_hdr, const int l3len);
 void *get_layer4_v6(const ipv6_hdr_t *ip_hdr, const int l3len);

+ 1 - 1
src/common/git_version.c

@@ -1,4 +1,4 @@
-const char GIT_Version[] = "git:v4.3.4";
+const char GIT_Version[] = "git:v4.4.0";
 const char *git_version(void) {
     return GIT_Version;
 }

+ 1 - 1
src/common/interface.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 1 - 1
src/common/interface.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 1 - 1
src/common/list.c

@@ -1,6 +1,6 @@
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 

+ 1 - 1
src/common/list.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta