1
0
Quellcode durchsuchen

Merge upstream version 4.4.1

Christoph Biedl vor 2 Jahren
Ursprung
Commit
a82360fd36
87 geänderte Dateien mit 477 neuen und 117 gelöschten Zeilen
  1. 86 10
      configure
  2. 75 1
      configure.ac
  3. 9 1
      docs/CHANGELOG
  4. 20 0
      src/common/err.h
  5. 36 0
      src/common/get.c
  6. 1 1
      src/common/git_version.c
  7. 3 0
      src/config.h.in
  8. 1 1
      src/tcpbridge.1
  9. 1 1
      src/tcpcapinfo.1
  10. 4 13
      src/tcpedit/checksum.c
  11. 107 39
      src/tcpedit/edit_packet.c
  12. 6 4
      src/tcpedit/edit_packet.h
  13. 10 11
      src/tcpedit/fuzzing.c
  14. 2 2
      src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.c
  15. 7 0
      src/tcpedit/plugins/dlt_plugins.c
  16. 26 1
      src/tcpedit/plugins/dlt_utils.c
  17. 2 0
      src/tcpedit/plugins_types.h
  18. 39 10
      src/tcpedit/tcpedit.c
  19. 3 0
      src/tcpedit/tcpedit_types.h
  20. 1 1
      src/tcpliveplay.1
  21. 1 1
      src/tcpprep.1
  22. 2 2
      src/tcpreplay-edit.1
  23. 2 2
      src/tcpreplay.1
  24. 7 1
      src/tcpreplay.c
  25. 1 1
      src/tcpreplay_opts.def
  26. 1 1
      src/tcprewrite.1
  27. 24 13
      src/tcprewrite.c
  28. BIN
      test/test.rewrite_1ttl
  29. BIN
      test/test.rewrite_2ttl
  30. BIN
      test/test.rewrite_3ttl
  31. BIN
      test/test.rewrite_config
  32. BIN
      test/test.rewrite_dlthdlc
  33. BIN
      test/test.rewrite_dltuser
  34. BIN
      test/test.rewrite_efcs
  35. BIN
      test/test.rewrite_endpoint
  36. BIN
      test/test.rewrite_enet_subsmac
  37. BIN
      test/test.rewrite_fixcsum
  38. BIN
      test/test.rewrite_fixlen_del
  39. BIN
      test/test.rewrite_fixlen_pad
  40. BIN
      test/test.rewrite_fixlen_trunc
  41. BIN
      test/test.rewrite_l7fuzzing
  42. BIN
      test/test.rewrite_layer2
  43. BIN
      test/test.rewrite_mac
  44. BIN
      test/test.rewrite_mac_seed
  45. BIN
      test/test.rewrite_mac_seed_keep
  46. BIN
      test/test.rewrite_mtutrunc
  47. BIN
      test/test.rewrite_pad
  48. BIN
      test/test.rewrite_pnat
  49. BIN
      test/test.rewrite_portmap
  50. BIN
      test/test.rewrite_range_portmap
  51. BIN
      test/test.rewrite_seed
  52. BIN
      test/test.rewrite_sequence
  53. BIN
      test/test.rewrite_skip
  54. BIN
      test/test.rewrite_tos
  55. BIN
      test/test.rewrite_trunc
  56. BIN
      test/test.rewrite_vlan802.1ad
  57. BIN
      test/test.rewrite_vlandel
  58. BIN
      test/test2.rewrite_1ttl
  59. BIN
      test/test2.rewrite_2ttl
  60. BIN
      test/test2.rewrite_3ttl
  61. BIN
      test/test2.rewrite_config
  62. BIN
      test/test2.rewrite_dlthdlc
  63. BIN
      test/test2.rewrite_dltuser
  64. BIN
      test/test2.rewrite_efcs
  65. BIN
      test/test2.rewrite_endpoint
  66. BIN
      test/test2.rewrite_enet_subsmac
  67. BIN
      test/test2.rewrite_fixcsum
  68. BIN
      test/test2.rewrite_fixlen_del
  69. BIN
      test/test2.rewrite_fixlen_pad
  70. BIN
      test/test2.rewrite_fixlen_trunc
  71. BIN
      test/test2.rewrite_l7fuzzing
  72. BIN
      test/test2.rewrite_layer2
  73. BIN
      test/test2.rewrite_mac
  74. BIN
      test/test2.rewrite_mac_seed
  75. BIN
      test/test2.rewrite_mac_seed_keep
  76. BIN
      test/test2.rewrite_mtutrunc
  77. BIN
      test/test2.rewrite_pad
  78. BIN
      test/test2.rewrite_pnat
  79. BIN
      test/test2.rewrite_portmap
  80. BIN
      test/test2.rewrite_range_portmap
  81. BIN
      test/test2.rewrite_seed
  82. BIN
      test/test2.rewrite_sequence
  83. BIN
      test/test2.rewrite_skip
  84. BIN
      test/test2.rewrite_tos
  85. BIN
      test/test2.rewrite_trunc
  86. BIN
      test/test2.rewrite_vlan802.1ad
  87. BIN
      test/test2.rewrite_vlandel

+ 86 - 10
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.4.0.
+# Generated by GNU Autoconf 2.69 for tcpreplay 4.4.1.
 #
 # 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.4.0'
-PACKAGE_STRING='tcpreplay 4.4.0'
+PACKAGE_VERSION='4.4.1'
+PACKAGE_STRING='tcpreplay 4.4.1'
 PACKAGE_BUGREPORT='https://github.com/appneta/tcpreplay/issues'
 PACKAGE_URL='http://tcpreplay.sourceforge.net/'
 
@@ -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.4.0 to adapt to many kinds of systems.
+\`configure' configures tcpreplay 4.4.1 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.4.0:";;
+     short | recursive ) echo "Configuration of tcpreplay 4.4.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1689,7 +1689,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-tcpreplay configure 4.4.0
+tcpreplay configure 4.4.1
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2649,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.4.0, which was
+It was created by tcpreplay $as_me 4.4.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3816,7 +3816,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='tcpreplay'
- VERSION='4.4.0'
+ VERSION='4.4.1'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -23262,6 +23262,82 @@ 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_os" in
+    darwin*)
+        # macOS M1 test fails due to lack of fork() so just hard code it
+        unaligned_cv_fail=no
+    ;;
+    *)
+        case "$host_cpu" in
+
+        # XXX: should also check that they don't do weird things
+        alpha*|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
+    ;;
+    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.
@@ -25797,7 +25873,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.4.0, which was
+This file was extended by tcpreplay $as_me 4.4.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -25864,7 +25940,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.4.0
+tcpreplay config.status 4.4.1
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 

+ 75 - 1
configure.ac

@@ -4,7 +4,7 @@ dnl $Id$
 AC_PREREQ([2.69])
 
 dnl Set version info here!
-AC_INIT([tcpreplay],[4.4.0],[https://github.com/appneta/tcpreplay/issues],[tcpreplay],[http://tcpreplay.sourceforge.net/])
+AC_INIT([tcpreplay],[4.4.1],[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)
@@ -1699,6 +1699,80 @@ 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_os" in
+    darwin*)
+        # macOS M1 test fails due to lack of fork() so just hard code it
+        unaligned_cv_fail=no
+    ;;
+    *)
+        case "$host_cpu" in
+
+        # XXX: should also check that they don't do weird things
+        alpha*|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
+    ;;
+    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 ##################################################

+ 9 - 1
docs/CHANGELOG

@@ -1,4 +1,12 @@
-06/19/2021 Version 4.4.0
+02/12/2022 Version 4.4.1
+    - fix support for piping PCAP files from STDIN (#708)
+    - build failures Debian/kfreebsd (#706)
+    - bus error when building on armhf (#705)
+    - typo fixes (#704)
+    - heap buffer overflow in tcpreplay (#703)
+    - double free in Juniper DLT (#702)
+
+01/31/2022 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)

+ 20 - 0
src/common/err.h

@@ -103,6 +103,16 @@ void notice(const char *fmt, ...);
         exit(x); \
     } while (0)
 
+#define err_no_exit(y) do { \
+        fprintf(stderr, "\nFatal Error in %s:%s() line %d:\n%s\n", __FILE__, __FUNCTION__, __LINE__, y); \
+        fflush(NULL); \
+    } while (0)
+
+#define err_no_exitx(y, ...) do {\
+        fprintf(stderr, "\nFatal Error in %s:%s() line %d:\n " y "\n", __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \
+        fflush(NULL); \
+    } while (0)
+
 #else /* no detailed DEBUG info */
 
 /* dbg() and dbgx() become no-ops for non-DEBUG builds */
@@ -124,6 +134,16 @@ void notice(const char *fmt, ...);
         fflush(NULL); \
         exit(x); \
     } while (0)
+
+#define err_no_exit(y) do {\
+        fprintf(stderr, "\nFatal Error:\n%s\n", y); \
+        fflush(NULL); \
+    } while(0)
+
+#define err_no_exitx(y, ...) do {\
+        fprintf(stderr, "\nFatal Error: " y "\n", __VA_ARGS__); \
+        fflush(NULL); \
+    } while (0)
 #endif /* DEBUG */
 
 

+ 36 - 0
src/common/get.c

@@ -460,11 +460,29 @@ get_ipv4(const u_char *pktdata, int datalen, int datalink, u_char **newbuff)
     l2len -= l2offset;
     pkt_len -= l2offset;
 
+#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 (l2len % sizeof(long)) {
+        memcpy(*newbuff, (packet + l2len), (pkt_len - l2len));
+        ip_hdr = *newbuff;
+    } else {
+
+        /* we don't have to do a memcpy if l2len lands on a boundary */
+        ip_hdr = (packet + l2len);
+    }
+#else
     /*
      * on non-strict byte align systems, don't need to memcpy(), 
      * just point to l2len bytes into the existing buffer
      */
     ip_hdr = (packet + l2len);
+#endif
 
     return ip_hdr;
 }
@@ -517,11 +535,29 @@ get_ipv6(const u_char *pktdata, int datalen, int datalink, u_char **newbuff)
     l2len -= l2offset;
     pkt_len -= l2offset;
 
+#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 (l2len % sizeof(long)) {
+        memcpy(*newbuff, (packet + l2len), (pkt_len - l2len));
+        ip6_hdr = *newbuff;
+    } else {
+
+        /* we don't have to do a memcpy if l2len lands on a boundary */
+        ip6_hdr = (packet + l2len);
+    }
+#else
     /*
      * on non-strict byte align systems, don't need to memcpy(),
      * just point to l2len bytes into the existing buffer
      */
     ip6_hdr = (packet + l2len);
+#endif
 
     return ip6_hdr;
 }

+ 1 - 1
src/common/git_version.c

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

+ 3 - 0
src/config.h.in

@@ -54,6 +54,9 @@
 /* fopen(3) accepts a 't' in the mode flag */
 #undef FOPEN_TEXT_FLAG
 
+/* Are we strictly aligned? */
+#undef FORCE_ALIGN
+
 /* Force using BPF for sending packet */
 #undef FORCE_INJECT_BPF
 

+ 1 - 1
src/tcpbridge.1

@@ -10,7 +10,7 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpbridge 1 "29 Jan 2022" "tcpbridge" "User Commands"
+.TH tcpbridge 1 "12 Feb 2022" "tcpbridge" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"

+ 1 - 1
src/tcpcapinfo.1

@@ -10,7 +10,7 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpcapinfo 1 "29 Jan 2022" "Tcpreplay Suite" "User Commands"
+.TH tcpcapinfo 1 "12 Feb 2022" "Tcpreplay Suite" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"

+ 4 - 13
src/tcpedit/checksum.c

@@ -154,24 +154,15 @@ do_checksum(tcpedit_t *tcpedit, uint8_t *data, int proto, int len) {
             icmp6->icmp_sum = CHECKSUM_CARRY(sum);
             break;
 
-        case IPPROTO_IP:
+        default:
             if (ipv4) {
                 ipv4->ip_sum = 0;
                 sum = do_checksum_math((uint16_t *)data, ip_hl);
                 ipv4->ip_sum = CHECKSUM_CARRY(sum);
+            } else {
+                tcpedit_setwarn(tcpedit, "Unsupported protocol for checksum: 0x%x", proto);
+                return TCPEDIT_WARN;
             }
-            break;
-
-        case IPPROTO_IGMP:
-        case IPPROTO_GRE:
-        case IPPROTO_OSPF:
-        case IPPROTO_OSPF_LSA:
-        case IPPROTO_VRRP:
-        case TCPR_PROTO_CDP:
-        case TCPR_PROTO_ISL:
-        default:
-            tcpedit_setwarn(tcpedit, "Unsupported protocol for checksum: 0x%x", proto);
-            return TCPEDIT_WARN;
     }
 
     return TCPEDIT_OK;

+ 107 - 39
src/tcpedit/edit_packet.c

@@ -43,8 +43,8 @@ static int is_unicast_ipv4(tcpedit_t *tcpedit, uint32_t ip);
 static void randomize_ipv6_addr(tcpedit_t *tcpedit, struct tcpr_in6_addr *addr);
 static int remap_ipv6(tcpedit_t *tcpedit, tcpr_cidr_t *cidr, struct tcpr_in6_addr *addr);
 static int is_multicast_ipv6(tcpedit_t *tcpedit, struct tcpr_in6_addr *addr);
-
-static int ipv6_header_length(ipv6_hdr_t const * ip6_hdr, int pkt_len);
+static int ipv6_header_length(ipv6_hdr_t const * ip6_hdr, const size_t pkt_len,
+                              const size_t l2len);
 
 /**
  * this code re-calcs the IP and Layer 4 checksums
@@ -56,36 +56,44 @@ static int ipv6_header_length(ipv6_hdr_t const * ip6_hdr, int pkt_len);
  * Returns 0 on success, -1 on error
  */
 int
-fix_ipv4_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr, ipv4_hdr_t *ip_hdr)
+fix_ipv4_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
+                   ipv4_hdr_t *ip_hdr, const size_t l2len)
 {
     int ret1 = 0, ret2 = 0, ip_len;
     assert(tcpedit);
     assert(pkthdr);
     assert(ip_hdr);
 
-    if (pkthdr->caplen < sizeof(*ip_hdr)) {
-        tcpedit_setwarn(tcpedit, "caplen too small to read IPv4 header: %u",
-                pkthdr->caplen);
+    if (pkthdr->caplen < (sizeof(*ip_hdr) + l2len)) {
+        tcpedit_setwarn(tcpedit, "caplen too small to read IPv4 header: caplen=%u: pkt=" COUNTER_SPEC,
+                pkthdr->caplen, tcpedit->runtime.packetnum);
         return TCPEDIT_WARN;
     }
 
     if (ip_hdr->ip_v != 4) {
-        tcpedit_seterr(tcpedit, "Invalid packet: Expected IPv4 packet: got %u", ip_hdr->ip_v);
+        tcpedit_seterr(tcpedit, "Invalid packet: Expected IPv4 packet: got %u: pkt=" COUNTER_SPEC,
+                       ip_hdr->ip_v, tcpedit->runtime.packetnum);
         return TCPEDIT_ERROR;
     }
 
+    ip_len = (int)ntohs(ip_hdr->ip_len);
     /* calc the L4 checksum if we have the whole packet && not a frag or first frag */
     if (pkthdr->caplen == pkthdr->len &&
             (htons(ip_hdr->ip_off) & (IP_MF | IP_OFFMASK)) == 0) {
-        ip_len = (int)ntohs(ip_hdr->ip_len);
-        ret1 = do_checksum(tcpedit, (u_char *) ip_hdr, ip_hdr->ip_p,
-                ip_len - (ip_hdr->ip_hl << 2));
+        if (ip_len != (int)(pkthdr->caplen - l2len)) {
+            tcpedit_seterr(tcpedit,
+                           "caplen minus L2 length %u does IPv4 header length %u: pkt=" COUNTER_SPEC,
+                           pkthdr->caplen - l2len, ip_len,
+                           tcpedit->runtime.packetnum);
+            return TCPEDIT_ERROR;
+        }
+        ret1 = do_checksum(tcpedit, (u_char*)ip_hdr, ip_hdr->ip_p,
+                           ip_len - (ip_hdr->ip_hl << 2));
         if (ret1 < 0)
             return TCPEDIT_ERROR;
     }
     
     /* calc IP checksum */
-    ip_len = (int)ntohs(ip_hdr->ip_len);
     ret2 = do_checksum(tcpedit, (u_char *) ip_hdr, IPPROTO_IP, ip_len);
     if (ret2 < 0)
         return TCPEDIT_ERROR;
@@ -102,7 +110,8 @@ fix_ipv4_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr, ipv4_hdr_t *i
  *         -1 on error
  */
 static int
-ipv6_header_length(ipv6_hdr_t const * ip6_hdr, int pkt_len)
+ipv6_header_length(ipv6_hdr_t const * ip6_hdr, const size_t pkt_len,
+                   const size_t l2len)
 {
     struct tcpr_ipv6_ext_hdr_base const * nhdr;
     uint8_t next_header;
@@ -111,8 +120,7 @@ ipv6_header_length(ipv6_hdr_t const * ip6_hdr, int pkt_len)
     offset = sizeof(*ip6_hdr);
     next_header = ip6_hdr->ip_nh;
 
-    while (sizeof(*nhdr) + offset < (size_t)pkt_len)
-    {
+    while (sizeof(*nhdr) + offset + l2len < (size_t)pkt_len) {
         if (next_header != TCPR_IPV6_NH_HBH
                 && next_header != TCPR_IPV6_NH_ROUTING
                 && next_header != TCPR_IPV6_NH_FRAGMENT) {
@@ -128,16 +136,17 @@ ipv6_header_length(ipv6_hdr_t const * ip6_hdr, int pkt_len)
 }
 
 int
-fix_ipv6_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr, ipv6_hdr_t *ip6_hdr)
+fix_ipv6_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
+                   ipv6_hdr_t *ip6_hdr, const size_t l2len)
 {
     int ret = 0;
     assert(tcpedit);
     assert(pkthdr);
     assert(ip6_hdr);
 
-    if (pkthdr->caplen < sizeof(*ip6_hdr)) {
-        tcpedit_setwarn(tcpedit, "caplen too small to read IPv6 header: %u",
-                pkthdr->caplen);
+    if (pkthdr->caplen < (sizeof(*ip6_hdr) + l2len)) {
+        tcpedit_setwarn(tcpedit, "caplen too small to read IPv6 header: caplen=%u pkt=" COUNTER_SPEC,
+                pkthdr->caplen, tcpedit->runtime.packetnum);
         return TCPEDIT_WARN;
     }
 
@@ -149,9 +158,10 @@ fix_ipv6_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr, ipv6_hdr_t *i
 
     /* calc the L4 checksum if we have the whole packet && not a frag or first frag */
     if (pkthdr->caplen == pkthdr->len) {
-        if (ip6_hdr->ip_len < ipv6_header_length(ip6_hdr, pkthdr->len)) {
-            tcpedit_setwarn(tcpedit, "Unable to checksum IPv6 packet with invalid length %u",
-                    ip6_hdr->ip_len);
+        int ip6_len = ipv6_header_length(ip6_hdr, pkthdr->len, l2len);
+        if (ip6_hdr->ip_len < ip6_len) {
+            tcpedit_setwarn(tcpedit, "Unable to checksum IPv6 packet with invalid: pkt=" COUNTER_SPEC " IP length=%u caplen=" COUNTER_SPEC,
+                           tcpedit->runtime.packetnum, ip6_hdr->ip_len);
             return TCPEDIT_WARN;
         }
         ret = do_checksum(tcpedit, (u_char *)ip6_hdr, ip6_hdr->ip_nh,
@@ -167,20 +177,6 @@ fix_ipv6_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr, ipv6_hdr_t *i
     return TCPEDIT_OK;
 }
 
-/*
- * #406 fix IP headers which may be not be set properly due to TCP segmentation
- */
-void fix_ipv4_length(struct pcap_pkthdr *pkthdr, ipv4_hdr_t *ip_hdr)
-{
-    if (!ip_hdr->ip_len)
-        ip_hdr->ip_len = htons((uint16_t)pkthdr->len);
-}
-
-void fix_ipv6_length(struct pcap_pkthdr *pkthdr, ipv6_hdr_t *ip6_hdr)
-{
-    if (!ip6_hdr->ip_len)
-        ip6_hdr->ip_len = htons((uint16_t)pkthdr->len);
-}
 
 static void ipv4_l34_csum_replace(uint8_t *data, uint8_t protocol,
         uint32_t old, uint32_t new)
@@ -369,6 +365,40 @@ randomize_ipv6_addr(tcpedit_t *tcpedit, struct tcpr_in6_addr *addr)
     }
 }
 
+int fix_ipv4_length(struct pcap_pkthdr *pkthdr, ipv4_hdr_t *ip_hdr,
+                           const size_t l2len)
+{
+    int ip_len = (int)ntohs(ip_hdr->ip_len);
+    int ip_len_want = (int)(pkthdr->len - l2len);
+
+    if (pkthdr->caplen < l2len + sizeof(*ip_hdr))
+        return -1;
+
+    if ((htons(ip_hdr->ip_off) & (IP_MF | IP_OFFMASK)) == 0 &&
+        ip_len != ip_len_want) {
+        ip_hdr->ip_len = htons(ip_len_want);
+        return 1;
+    }
+
+    return 0;
+}
+
+int fix_ipv6_length(struct pcap_pkthdr *pkthdr, ipv6_hdr_t *ip6_hdr,
+                           const size_t l2len)
+{
+    int ip_len = ntohs((uint16_t)ip6_hdr->ip_len);
+    int ip_len_want = (int)(pkthdr->len - l2len - sizeof(*ip6_hdr));
+
+    if (pkthdr->caplen < l2len + sizeof(*ip6_hdr))
+        return -1;
+
+    if (ip_len != ip_len_want) {
+        ip6_hdr->ip_len = htons((uint16_t)ip_len_want);
+        return 1;
+    }
+
+    return 0;
+}
 
 /**
  * randomizes the source and destination IP addresses based on a 
@@ -446,8 +476,8 @@ randomize_ipv6(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
     /* randomize IP addresses based on the value of random */
     dbgx(1, "Old Src IP: %s\tOld Dst IP: %s", srcip, dstip);
     if (l3len < (int)sizeof(ipv6_hdr_t)) {
-        tcpedit_seterr(tcpedit, "Unable to randomize IPv6 header due to packet capture snap length %u",
-                pkthdr->caplen);
+        tcpedit_seterr(tcpedit, "Unable to randomize IPv6 header due to packet capture snap length %u: pkt=" COUNTER_SPEC,
+                pkthdr->caplen, tcpedit->runtime.packetnum);
         return TCPEDIT_ERROR;
     }
 
@@ -953,6 +983,9 @@ randomize_iparp(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
 {
     arp_hdr_t *arp_hdr ;
     int l2len;
+#ifdef FORCE_ALIGN
+    uint32_t iptemp;
+#endif
 
     assert(tcpedit);
     assert(pkthdr);
@@ -979,12 +1012,30 @@ randomize_iparp(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
         u_char *add_hdr = ((u_char *)arp_hdr) + sizeof(arp_hdr_t) +
                 arp_hdr->ar_hln;
 
+#ifdef FORCE_ALIGN
+        /* copy IP to a temporary buffer for processing */
+        memcpy(&iptemp, add_hdr, sizeof(uint32_t));
+        ip = &iptemp;
+#else
         ip = (uint32_t *)add_hdr;
+#endif
         *ip = randomize_ipv4_addr(tcpedit, *ip);
+#ifdef FORCE_ALIGN
+        memcpy(add_hdr, &iptemp, sizeof(uint32_t));
+#endif
 
         add_hdr += arp_hdr->ar_pln + arp_hdr->ar_hln;
+#ifdef FORCE_ALIGN
+        /* copy IP2 to a temporary buffer for processing */
+        memcpy(&iptemp, add_hdr, sizeof(uint32_t));
+        ip = &iptemp;
+#else
         ip = (uint32_t *)add_hdr;
+#endif
         *ip = randomize_ipv4_addr(tcpedit, *ip);
+#ifdef FORCE_ALIGN
+        memcpy(add_hdr, &iptemp, sizeof(uint32_t));
+#endif
     }
 
     return 1; /* yes we changed the packet */
@@ -1006,6 +1057,9 @@ rewrite_iparp(tcpedit_t *tcpedit, arp_hdr_t *arp_hdr, int cache_mode)
     uint32_t newip = 0;
     tcpr_cidrmap_t *cidrmap1 = NULL, *cidrmap2 = NULL;
     int didsrc = 0, diddst = 0, loop = 1;
+#ifdef FORCE_ALIGN
+    uint32_t iptemp;
+#endif
 
     assert(tcpedit);
     assert(arp_hdr);
@@ -1037,7 +1091,14 @@ rewrite_iparp(tcpedit_t *tcpedit, arp_hdr_t *arp_hdr, int cache_mode)
         add_hdr += sizeof(arp_hdr_t) + arp_hdr->ar_hln;
         ip1 = (uint32_t *)add_hdr;
         add_hdr += arp_hdr->ar_pln + arp_hdr->ar_hln;
+#ifdef FORCE_ALIGN
+        /* copy IP2 to a temporary buffer for processing */
+        memcpy(&iptemp, add_hdr, sizeof(uint32_t));
+        ip2 = &iptemp;
+#else
         ip2 = (uint32_t *)add_hdr;
+#endif
+        
 
         /* loop through the cidrmap to rewrite */
         do {
@@ -1068,24 +1129,31 @@ rewrite_iparp(tcpedit_t *tcpedit, arp_hdr_t *arp_hdr, int cache_mode)
                 }
             }
 
+#ifdef FORCE_ALIGN
+            /* copy temporary IP to IP2 location in buffer */
+            memcpy(add_hdr, &iptemp, sizeof(uint32_t));
+#endif
+
             /*
              * loop while we haven't modified both src/dst AND
              * at least one of the cidr maps have a next pointer
              */
             if ((! (diddst && didsrc)) &&
                 (! ((cidrmap1->next == NULL) && (cidrmap2->next == NULL)))) {
-
+                
                 /* increment our ptr's if possible */
                 if (cidrmap1->next != NULL)
                     cidrmap1 = cidrmap1->next;
-
+                
                 if (cidrmap2->next != NULL)
                     cidrmap2 = cidrmap2->next;
+                
             } else {
                 loop = 0;
             }
 
         } while (loop);
+        
     } else {
         warn("ARP packet isn't for IPv4!  Can't rewrite IP's");
     }

+ 6 - 4
src/tcpedit/edit_packet.h

@@ -37,14 +37,16 @@ int randomize_iparp(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
         u_char *pktdata, int datalink, const int l3len);
 
 int fix_ipv4_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkdhdr,
-        ipv4_hdr_t *ip_hdr);
+                       ipv4_hdr_t *ip_hdr, const size_t l2len);
 
 int fix_ipv6_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkdhdr,
-        ipv6_hdr_t *ip_hdr);
+                       ipv6_hdr_t *ip_hdr, const size_t l2len);
 
-void fix_ipv4_length(struct pcap_pkthdr *pkthdr, ipv4_hdr_t *ip_hdr);
+int fix_ipv4_length(struct pcap_pkthdr *pkthdr, ipv4_hdr_t *ip_hdr,
+                           const size_t l2len);
 
-void fix_ipv6_length(struct pcap_pkthdr *pkthdr, ipv6_hdr_t *ip6_hdr);
+int fix_ipv6_length(struct pcap_pkthdr *pkthdr, ipv6_hdr_t *ip6_hdr,
+                           const size_t l2len);
 
 int extract_data(tcpedit_t *tcpedit, const u_char *pktdata, 
         int caplen, char *l7data[]);

+ 10 - 11
src/tcpedit/fuzzing.c

@@ -79,7 +79,7 @@ fuzzing(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
     uint8_t l4proto;
     u_char *packet, *l3data, *l4data;
     tcpeditdlt_plugin_t *plugin;
-    int caplen, l2len, l4len;
+    int l2len, l4len;
     tcpeditdlt_t *ctx;
 
     assert(tcpedit);
@@ -102,11 +102,10 @@ fuzzing(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
     /* initializations */
     ctx = tcpedit->dlt_ctx;
     packet = *pktdata;
-    caplen = pkthdr->caplen;
     plugin = tcpedit->dlt_ctx->encoder;
-    l2len = plugin->plugin_l2len(ctx, packet, caplen);
-    l2proto = ntohs(plugin->plugin_proto(ctx, packet, caplen));
-    if (l2len == -1 || caplen < l2len)
+    l2len = plugin->plugin_l2len(ctx, packet, pkthdr->caplen);
+    l2proto = ntohs(plugin->plugin_proto(ctx, packet, pkthdr->caplen));
+    if (l2len == -1 || (int)pkthdr->caplen < l2len)
         goto done;
 
     /*
@@ -116,15 +115,15 @@ fuzzing(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
      * to '*pktdata'. All alterations are done in this buffer, which later
      * will be copied back to '*pktdata', if necessary
      */
-    l3data = plugin->plugin_get_layer3(ctx, packet, caplen);
+    l3data = plugin->plugin_get_layer3(ctx, packet, pkthdr->caplen);
     if (!l3data)
         goto done;
 
-    l4len = caplen - l2len;
+    l4len = pkthdr->caplen - l2len;
     switch (l2proto) {
     case (ETHERTYPE_IP):
     {
-        l4data = get_layer4_v4((ipv4_hdr_t*)l3data, caplen - l2len);
+        l4data = get_layer4_v4((ipv4_hdr_t*)l3data, pkthdr->caplen - l2len);
         if (!l4data)
             goto done;
 
@@ -132,7 +131,7 @@ fuzzing(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
         break;
     }
     case (ETHERTYPE_IP6): {
-        l4data = get_layer4_v6((ipv6_hdr_t*)l3data, caplen - l2len);
+        l4data = get_layer4_v6((ipv6_hdr_t*)l3data, pkthdr->caplen - l2len);
         if (!l4data)
             goto done;
 
@@ -309,9 +308,9 @@ fuzzing(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr,
     /* in cases where 'l3data' is a working buffer, copy it back to '*pkthdr' */
     plugin->plugin_merge_layer3(ctx,
                                 packet,
-                                caplen,
+                                pkthdr->caplen,
                                 (l2proto == ETHERTYPE_IP) ? l4data : NULL,
-                                (l2proto == ETHERTYPE_IPV6) ? l4data : NULL);
+                                (l2proto == ETHERTYPE_IP6) ? l4data : NULL);
 
 done:
     return packet_changed;

+ 2 - 2
src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.c

@@ -138,7 +138,8 @@ dlt_jnpr_ether_post_init(tcpeditdlt_t *ctx)
     
     /* init our subcontext & decoder of en10mb */
     config = (jnpr_ether_config_t *)ctx->encoder->config;
-    config->subctx = tcpedit_dlt_init(ctx->tcpedit, DLT_EN10MB);
+    if (config->subctx == NULL)
+        config->subctx = tcpedit_dlt_init(ctx->tcpedit, DLT_EN10MB);
         
     return TCPEDIT_OK;
 }
@@ -168,7 +169,6 @@ dlt_jnpr_ether_cleanup(tcpeditdlt_t *ctx)
 
         config = (jnpr_ether_config_t *)ctx->encoder->config;
         tcpedit_dlt_cleanup(config->subctx);
-        safe_free(config->subctx);
         safe_free(plugin->config);
         plugin->config = NULL;
         plugin->config_size = 0;

+ 7 - 0
src/tcpedit/plugins/dlt_plugins.c

@@ -130,6 +130,9 @@ tcpedit_dlt_init(tcpedit_t *tcpedit, const int srcdlt)
     ctx = (tcpeditdlt_t *)safe_malloc(sizeof(tcpeditdlt_t));
 
     /* do we need a side buffer for L3 data? */
+#ifdef FORCE_ALIGN
+    ctx->l3buff = (u_char *)safe_malloc(MAXPACKET);
+#endif
 
     /* copy our tcpedit context */
     ctx->tcpedit = tcpedit;
@@ -471,6 +474,10 @@ tcpedit_dlt_cleanup(tcpeditdlt_t *ctx)
         plugin = plugin_next;
     }
 
+#ifdef FORCE_ALIGN
+    safe_free(ctx->l3buff);
+#endif
+
     if (ctx->decoded_extra != NULL) {
         safe_free(ctx->decoded_extra);
         ctx->decoded_extra = NULL;

+ 26 - 1
src/tcpedit/plugins/dlt_utils.c

@@ -203,11 +203,28 @@ tcpedit_dlt_l3data_copy(tcpeditdlt_t *ctx, u_char *packet, int pktlen, int l2len
 
     if (pktlen <= l2len)
         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 (l2len % 4 == 0) {
+        ptr = (&(packet)[l2len]);
+    } else {
+        ptr = ctx->l3buff;
+        memcpy(ptr, (&(packet)[l2len]), pktlen - l2len);
+    }
+#else
     /*
+     * on non-strict byte align systems, don't need to memcpy(), 
      * just point to 14 bytes into the existing buffer
      */
     ptr = (&(packet)[l2len]);
+#endif
     return ptr;
 }
 
@@ -222,6 +239,14 @@ tcpedit_dlt_l3data_merge(tcpeditdlt_t *ctx, u_char *packet, int pktlen, const u_
     assert(pktlen >= 0);
     assert(l3data);
     assert(l2len >= 0);
+#ifdef FORCE_ALIGN
+    /* 
+     * put back the layer 3 and above back in the pkt.data buffer 
+     * we can't edit the packet at layer 3 or above beyond this point
+     */
+     if (l2len % 4 != 0)
+         memcpy((&(packet)[l2len]), l3data, pktlen - l2len);
+#endif
     return packet;
 }
 

+ 2 - 0
src/tcpedit/plugins_types.h

@@ -103,7 +103,9 @@ struct tcpeditdlt_plugin_s {
  */
 struct tcpeditdlt_s {
     tcpedit_t *tcpedit;                 /* pointer to our tcpedit context */
+#ifdef FORCE_ALIGN
     u_char *l3buff;                     /* pointer for L3 buffer on strictly aligned systems */
+#endif
     tcpeditdlt_plugin_t *plugins;       /* registered plugins */
     tcpeditdlt_plugin_t *decoder;       /* Encoder plugin */
     tcpeditdlt_plugin_t *encoder;       /* Decoder plugin */      

+ 39 - 10
src/tcpedit/tcpedit.c

@@ -84,15 +84,17 @@ int
 tcpedit_packet(tcpedit_t *tcpedit, struct pcap_pkthdr **pkthdr,
         u_char **pktdata, tcpr_dir_t direction)
 {
-    ipv4_hdr_t *ip_hdr = NULL;
-    ipv6_hdr_t *ip6_hdr = NULL;
-    arp_hdr_t *arp_hdr = NULL;
-    int l2len, l2proto, retval = 0;
+    bool fuzz_once = tcpedit->fuzz_seed != 0;
+    ipv4_hdr_t *ip_hdr;
+    ipv6_hdr_t *ip6_hdr;
+    arp_hdr_t *arp_hdr;
+    int l2len, l2proto, retval;
     int dst_dlt, src_dlt, pktlen, lendiff;
-    int ipflags = 0, tclass = 0;
-    int needtorecalc = 0;           /* did the packet change? if so, checksum */
+    int ipflags, tclass;
+    int needtorecalc;           /* did the packet change? if so, checksum */
     u_char *packet;
 
+
     assert(tcpedit);
     assert(pkthdr);
     assert(*pkthdr);
@@ -123,6 +125,14 @@ tcpedit_packet(tcpedit_t *tcpedit, struct pcap_pkthdr **pkthdr,
 
     src_dlt = tcpedit_dlt_src(tcpedit->dlt_ctx);
     
+    needtorecalc = 0;
+again:
+    ip_hdr = NULL;
+    ip6_hdr = NULL;
+    arp_hdr = NULL;
+    retval = 0;
+    ipflags = 0;
+    tclass = 0;
     /* not everything has a L3 header, so check for errors.  returns proto in network byte order */
     if ((l2proto = tcpedit_dlt_proto(tcpedit->dlt_ctx, src_dlt, packet, (*pkthdr)->caplen)) < 0) {
         dbgx(2, "Packet has no L3+ header: %s", tcpedit_geterr(tcpedit));
@@ -272,12 +282,14 @@ tcpedit_packet(tcpedit_t *tcpedit, struct pcap_pkthdr **pkthdr,
             rewrite_ipv6_tcp_sequence(tcpedit, &ip6_hdr, (*pkthdr)->caplen - l2len);
     }
 
-    if (tcpedit->fuzz_seed != 0) {
+    if (fuzz_once) {
+        fuzz_once = false;
         retval = fuzzing(tcpedit, *pkthdr, pktdata);
         if (retval < 0) {
             return TCPEDIT_ERROR;
         }
         needtorecalc += retval;
+        goto again;
     }
 
     /* (Un)truncate or MTU truncate packet? */
@@ -344,14 +356,22 @@ tcpedit_packet(tcpedit_t *tcpedit, struct pcap_pkthdr **pkthdr,
         }
     }
 
+    /* ensure IP header length is correct */
+    if (ip_hdr != NULL) {
+        needtorecalc |= fix_ipv4_length(*pkthdr, ip_hdr, l2len);
+            needtorecalc = 1;
+    } else if (ip6_hdr != NULL) {
+        needtorecalc |= fix_ipv6_length(*pkthdr, ip6_hdr, l2len);
+    }
+
     /* do we need to fix checksums? -- must always do this last! */
-    if ((tcpedit->fixcsum || needtorecalc)) {
+    if ((tcpedit->fixcsum || needtorecalc > 0)) {
         if (ip_hdr != NULL) {
             dbgx(3, "doing IPv4 checksum: needtorecalc=%d", needtorecalc);
-            retval = fix_ipv4_checksums(tcpedit, *pkthdr, ip_hdr);
+            retval = fix_ipv4_checksums(tcpedit, *pkthdr, ip_hdr, l2len);
         } else if (ip6_hdr != NULL) {
             dbgx(3, "doing IPv6 checksum: needtorecalc=%d", needtorecalc);
-            retval = fix_ipv6_checksums(tcpedit, *pkthdr, ip6_hdr);
+            retval = fix_ipv6_checksums(tcpedit, *pkthdr, ip6_hdr, l2len);
         } else {
             dbgx(3, "checksum not performed: needtorecalc=%d", needtorecalc);
             retval = TCPEDIT_OK;
@@ -405,6 +425,10 @@ tcpedit_init(tcpedit_t **tcpedit_ex, int dlt)
     dbgx(1, "Input file (1) datalink type is %s",
             pcap_datalink_val_to_name(dlt));
 
+#ifdef FORCE_ALIGN
+    tcpedit->runtime.l3buff = (u_char *)safe_malloc(MAXPACKET);
+#endif
+
     return TCPEDIT_OK;
 }
 
@@ -619,6 +643,11 @@ tcpedit_close(tcpedit_t **tcpedit_ex)
         tcpedit->portmap = NULL;
     }
 
+#ifdef FORCE_ALIGN
+    safe_free(tcpedit->runtime.l3buff);
+    tcpedit->runtime.l3buff = NULL;
+#endif
+
     safe_free(*tcpedit_ex);
     *tcpedit_ex = NULL;
 

+ 3 - 0
src/tcpedit/tcpedit_types.h

@@ -69,6 +69,9 @@ typedef struct {
     int dlt2;
     char errstr[TCPEDIT_ERRSTR_LEN];
     char warnstr[TCPEDIT_ERRSTR_LEN];
+#ifdef FORCE_ALIGN    
+    u_char *l3buff;
+#endif
 } tcpedit_runtime_t;
 
 /*

+ 1 - 1
src/tcpliveplay.1

@@ -10,7 +10,7 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpliveplay 1 "28 Jan 2022" "tcpliveplay" "User Commands"
+.TH tcpliveplay 1 "12 Feb 2022" "tcpliveplay" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"

+ 1 - 1
src/tcpprep.1

@@ -10,7 +10,7 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpprep 1 "29 Jan 2022" "tcpprep" "User Commands"
+.TH tcpprep 1 "12 Feb 2022" "tcpprep" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"

+ 2 - 2
src/tcpreplay-edit.1

@@ -10,7 +10,7 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpreplay-edit 1 "29 Jan 2022" "tcpreplay" "User Commands"
+.TH tcpreplay-edit 1 "12 Feb 2022" "tcpreplay" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"
@@ -884,7 +884,7 @@ This option must not appear in combination with any of the following options:
 seed, fuzz-seed.
 .sp
 Ensure IPv4 and IPv6 packets will be unique for each \fB--loop\fP iteration. 
-This is done in a way that will not alter packet CRC, and therefore will genrally
+This is done in a way that will not alter packet CRC, and therefore will generally
 not affect performance. This option will significantly increase the flows/sec over
 generated over multiple loop iterations.
 .TP

+ 2 - 2
src/tcpreplay.1

@@ -10,7 +10,7 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpreplay 1 "29 Jan 2022" "tcpreplay" "User Commands"
+.TH tcpreplay 1 "12 Feb 2022" "tcpreplay" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"
@@ -359,7 +359,7 @@ This option must appear in combination with the following options:
 loop.
 .sp
 Ensure IPv4 and IPv6 packets will be unique for each \fB--loop\fP iteration. 
-This is done in a way that will not alter packet CRC, and therefore will genrally
+This is done in a way that will not alter packet CRC, and therefore will generally
 not affect performance. This option will significantly increase the flows/sec over
 generated over multiple loop iterations.
 .TP

+ 7 - 1
src/tcpreplay.c

@@ -116,9 +116,15 @@ main(int argc, char *argv[])
     for (i = 0; i < argc; i++) {
 #ifdef HAVE_FTS_H
         struct stat statbuf;
+
+        if (!strcmp(argv[i], "-")) {
+            tcpreplay_add_pcapfile(ctx, argv[i]);
+            continue;
+        }
+
         if (stat(argv[i], &statbuf) != 0) {
             errx(-1,
-                 "Unable to retrieve informations from file %s: %s",
+                 "Unable to retrieve information from file %s: %s",
                  argv[i],
                  strerror(errno));
         }

+ 1 - 1
src/tcpreplay_opts.def

@@ -479,7 +479,7 @@ flag = {
     descrip     = "Modify IP addresses each loop iteration to generate unique flows";
     doc         = <<- EOText
 Ensure IPv4 and IPv6 packets will be unique for each @var{--loop} iteration. 
-This is done in a way that will not alter packet CRC, and therefore will genrally
+This is done in a way that will not alter packet CRC, and therefore will generally
 not affect performance. This option will significantly increase the flows/sec over
 generated over multiple loop iterations.
 EOText;

+ 1 - 1
src/tcprewrite.1

@@ -10,7 +10,7 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcprewrite 1 "29 Jan 2022" "tcprewrite" "User Commands"
+.TH tcprewrite 1 "12 Feb 2022" "tcprewrite" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"

+ 24 - 13
src/tcprewrite.c

@@ -80,22 +80,26 @@ main(int argc, char *argv[])
 
     /* init tcpedit context */
     if (tcpedit_init(&tcpedit, pcap_datalink(options.pin)) < 0) {
-        errx(-1, "Error initializing tcpedit: %s", tcpedit_geterr(tcpedit));
+        err_no_exitx("Error initializing tcpedit: %s", tcpedit_geterr(tcpedit));
+        tcpedit_close(&tcpedit);
+        exit(-1);
     }
 
     /* parse the tcpedit args */
     rcode = tcpedit_post_args(tcpedit);
     if (rcode < 0) {
+        err_no_exitx("Unable to parse args: %s", tcpedit_geterr(tcpedit));
         tcpedit_close(&tcpedit);
-        errx(-1, "Unable to parse args: %s", tcpedit_geterr(tcpedit));
+        exit(-1);
     } else if (rcode == 1) {
         warnx("%s", tcpedit_geterr(tcpedit));
     }
 
     if (tcpedit_validate(tcpedit) < 0) {
-        tcpedit_close(&tcpedit);
-        errx(-1, "Unable to edit packets given options:\n%s",
+        err_no_exitx("Unable to edit packets given options:\n%s",
                 tcpedit_geterr(tcpedit));
+        tcpedit_close(&tcpedit);
+        exit(-1);
     }
 
     /* fuzzing init */
@@ -116,8 +120,9 @@ main(int argc, char *argv[])
 #ifdef ENABLE_FRAGROUTE
     if (options.fragroute_args) {
         if ((options.frag_ctx = fragroute_init(65535, pcap_datalink(dlt_pcap), options.fragroute_args, ebuf)) == NULL) {
+            err_no_exitx("%s", ebuf);
             tcpedit_close(&tcpedit);
-            errx(-1, "%s", ebuf);
+            exit(-1);
         }
     }
 #endif
@@ -129,16 +134,18 @@ main(int argc, char *argv[])
 #endif
 
     if ((options.pout = pcap_dump_open(dlt_pcap, options.outfile)) == NULL) {
+        err_no_exitx("Unable to open output pcap file: %s", pcap_geterr(dlt_pcap));
         tcpedit_close(&tcpedit);
-        errx(-1, "Unable to open output pcap file: %s", pcap_geterr(dlt_pcap));
+        exit(-1);
     }
 
     pcap_close(dlt_pcap);
 
     /* rewrite packets */
-    if (rewrite_packets(tcpedit, options.pin, options.pout) != 0) {
+    if (rewrite_packets(tcpedit, options.pin, options.pout) == TCPEDIT_ERROR) {
+        err_no_exitx("Error rewriting packets: %s", tcpedit_geterr(tcpedit));
         tcpedit_close(&tcpedit);
-        errx(-1, "Error rewriting packets: %s", tcpedit_geterr(tcpedit));
+        exit(-1);
     }
 
     /* clean up after ourselves */
@@ -295,7 +302,7 @@ rewrite_packets(tcpedit_t *tcpedit, pcap_t *pin, pcap_dumper_t *pout)
             goto WRITE_PACKET; /* still need to write it so cache stays in sync */
 
         if ((rcode = tcpedit_packet(tcpedit, &pkthdr_ptr, pktdata, cache_result)) == TCPEDIT_ERROR) {
-            return -1;
+            return rcode;
         } else if ((rcode == TCPEDIT_SOFT_ERROR) && HAVE_OPT(SKIP_SOFT_ERRORS)) {
             /* don't write packet */
             dbgx(1, "Packet " COUNTER_SPEC " is suppressed from being written due to soft errors", packetnum);
@@ -311,7 +318,8 @@ WRITE_PACKET:
 #ifdef ENABLE_FRAGROUTE
         if (options.frag_ctx == NULL) {
             /* write the packet when there's no fragrouting to be done */
-            pcap_dump((u_char *)pout, pkthdr_ptr, *pktdata);
+            if (pkthdr_ptr->caplen)
+                pcap_dump((u_char *)pout, pkthdr_ptr, *pktdata);
         } else {
             /* get the L3 protocol of the packet */
             proto = tcpedit_l3proto(tcpedit, AFTER_PROCESS, *pktdata, pkthdr_ptr->caplen);
@@ -332,16 +340,19 @@ WRITE_PACKET:
                     dbgx(1, "processing packet " COUNTER_SPEC " frag: %u (%d)", packetnum, i++, frag_len);
                     pkthdr_ptr->caplen = frag_len;
                     pkthdr_ptr->len = frag_len;
-                    pcap_dump((u_char *)pout, pkthdr_ptr, (u_char *)frag);
+                    if (pkthdr_ptr->caplen)
+                        pcap_dump((u_char *)pout, pkthdr_ptr, (u_char *)frag);
                 }
             } else {
                 /* write the packet without fragroute */
-                pcap_dump((u_char *)pout, pkthdr_ptr, *pktdata);
+                if (pkthdr_ptr->caplen)
+                    pcap_dump((u_char *)pout, pkthdr_ptr, *pktdata);
             }
         }
 #else
     /* write the packet when there's no fragrouting to be done */
-    pcap_dump((u_char *)pout, pkthdr_ptr, *pktdata);
+    if (pkthdr_ptr->caplen)
+        pcap_dump((u_char *)pout, pkthdr_ptr, *pktdata);
 
 #endif
     } /* while() */

BIN
test/test.rewrite_1ttl


BIN
test/test.rewrite_2ttl


BIN
test/test.rewrite_3ttl


BIN
test/test.rewrite_config


BIN
test/test.rewrite_dlthdlc


BIN
test/test.rewrite_dltuser


BIN
test/test.rewrite_efcs


BIN
test/test.rewrite_endpoint


BIN
test/test.rewrite_enet_subsmac


BIN
test/test.rewrite_fixcsum


BIN
test/test.rewrite_fixlen_del


BIN
test/test.rewrite_fixlen_pad


BIN
test/test.rewrite_fixlen_trunc


BIN
test/test.rewrite_l7fuzzing


BIN
test/test.rewrite_layer2


BIN
test/test.rewrite_mac


BIN
test/test.rewrite_mac_seed


BIN
test/test.rewrite_mac_seed_keep


BIN
test/test.rewrite_mtutrunc


BIN
test/test.rewrite_pad


BIN
test/test.rewrite_pnat


BIN
test/test.rewrite_portmap


BIN
test/test.rewrite_range_portmap


BIN
test/test.rewrite_seed


BIN
test/test.rewrite_sequence


BIN
test/test.rewrite_skip


BIN
test/test.rewrite_tos


BIN
test/test.rewrite_trunc


BIN
test/test.rewrite_vlan802.1ad


BIN
test/test.rewrite_vlandel


BIN
test/test2.rewrite_1ttl


BIN
test/test2.rewrite_2ttl


BIN
test/test2.rewrite_3ttl


BIN
test/test2.rewrite_config


BIN
test/test2.rewrite_dlthdlc


BIN
test/test2.rewrite_dltuser


BIN
test/test2.rewrite_efcs


BIN
test/test2.rewrite_endpoint


BIN
test/test2.rewrite_enet_subsmac


BIN
test/test2.rewrite_fixcsum


BIN
test/test2.rewrite_fixlen_del


BIN
test/test2.rewrite_fixlen_pad


BIN
test/test2.rewrite_fixlen_trunc


BIN
test/test2.rewrite_l7fuzzing


BIN
test/test2.rewrite_layer2


BIN
test/test2.rewrite_mac


BIN
test/test2.rewrite_mac_seed


BIN
test/test2.rewrite_mac_seed_keep


BIN
test/test2.rewrite_mtutrunc


BIN
test/test2.rewrite_pad


BIN
test/test2.rewrite_pnat


BIN
test/test2.rewrite_portmap


BIN
test/test2.rewrite_range_portmap


BIN
test/test2.rewrite_seed


BIN
test/test2.rewrite_sequence


BIN
test/test2.rewrite_skip


BIN
test/test2.rewrite_tos


BIN
test/test2.rewrite_trunc


BIN
test/test2.rewrite_vlan802.1ad


BIN
test/test2.rewrite_vlandel