Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package tcpreplay for openSUSE:Factory 
checked in at 2026-07-26 11:30:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/tcpreplay (Old)
 and      /work/SRC/openSUSE:Factory/.tcpreplay.new.2004 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "tcpreplay"

Sun Jul 26 11:30:11 2026 rev:19 rq:1367775 version:4.5.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/tcpreplay/tcpreplay.changes      2026-07-24 
22:06:47.732753385 +0200
+++ /work/SRC/openSUSE:Factory/.tcpreplay.new.2004/tcpreplay.changes    
2026-07-26 11:32:44.499533984 +0200
@@ -1,0 +2,18 @@
+Sat Jul 25 19:11:23 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to version 4.5.5 - a security release:
+  * Fix heap buffer over-read in get_layer4_v6(), reachable by
+    reading an untrusted pcap with any of the tools
+    (GHSA-jj65-mrgg-f5fx)
+  * Fix stack buffer overflow in the fragroute rules-file parser
+    (GHSA-777w-9599-w8g4)
+  * Fix out-of-bounds write on an empty fragroute rules file
+    (GHSA-p7xp-4gj2-x56c)
+  * Fix off-by-one heap overflows in the fragroute ip_chaff and
+    tcp_chaff modules (GHSA-m655-53p4-6qm8, GHSA-v8c4-9w98-9v6v)
+  * Fix heap overflow via negative fragment/segment sizes in the
+    fragroute ip_frag and tcp_seg modules (GHSA-27v4-xhfx-g2rx)
+  * Harden fragroute allocation-failure and rule-list cleanup
+    paths and add the first fragroute test cases
+
+-------------------------------------------------------------------

Old:
----
  tcpreplay-4.5.4.tar.xz
  tcpreplay-4.5.4.tar.xz.asc

New:
----
  tcpreplay-4.5.5.tar.xz
  tcpreplay-4.5.5.tar.xz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ tcpreplay.spec ++++++
--- /var/tmp/diff_new_pack.012bAc/_old  2026-07-26 11:32:46.483602342 +0200
+++ /var/tmp/diff_new_pack.012bAc/_new  2026-07-26 11:32:46.499602893 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           tcpreplay
-Version:        4.5.4
+Version:        4.5.5
 Release:        0
 Summary:        Network analysis and testing tools
 License:        GPL-3.0-only

++++++ tcpreplay-4.5.4.tar.xz -> tcpreplay-4.5.5.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/configure 
new/tcpreplay-4.5.5/configure
--- old/tcpreplay-4.5.4/configure       2026-07-23 03:52:25.000000000 +0200
+++ new/tcpreplay-4.5.5/configure       2026-07-24 02:46:48.000000000 +0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.72 for tcpreplay 4.5.4.
+# Generated by GNU Autoconf 2.72 for tcpreplay 4.5.5.
 #
 # Report bugs to <https://github.com/appneta/tcpreplay/issues>.
 #
@@ -614,8 +614,8 @@
 # Identity of this package.
 PACKAGE_NAME='tcpreplay'
 PACKAGE_TARNAME='tcpreplay'
-PACKAGE_VERSION='4.5.4'
-PACKAGE_STRING='tcpreplay 4.5.4'
+PACKAGE_VERSION='4.5.5'
+PACKAGE_STRING='tcpreplay 4.5.5'
 PACKAGE_BUGREPORT='https://github.com/appneta/tcpreplay/issues'
 PACKAGE_URL='http://tcpreplay.sourceforge.net/'
 
@@ -1477,7 +1477,7 @@
   # 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.5.4 to adapt to many kinds of systems.
+'configure' configures tcpreplay 4.5.5 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1549,7 +1549,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of tcpreplay 4.5.4:";;
+     short | recursive ) echo "Configuration of tcpreplay 4.5.5:";;
    esac
   cat <<\_ACEOF
 
@@ -1726,7 +1726,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-tcpreplay configure 4.5.4
+tcpreplay configure 4.5.5
 generated by GNU Autoconf 2.72
 
 Copyright (C) 2023 Free Software Foundation, Inc.
@@ -2673,7 +2673,7 @@
 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.5.4, which was
+It was created by tcpreplay $as_me 4.5.5, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -4684,7 +4684,7 @@
 
 # Define the identity of the package.
  PACKAGE='tcpreplay'
- VERSION='4.5.4'
+ VERSION='4.5.5'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -30125,7 +30125,7 @@
 # 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.5.4, which was
+This file was extended by tcpreplay $as_me 4.5.5, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -30194,7 +30194,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-tcpreplay config.status 4.5.4
+tcpreplay config.status 4.5.5
 configured by $0, generated by GNU Autoconf 2.72,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/configure.ac 
new/tcpreplay-4.5.5/configure.ac
--- old/tcpreplay-4.5.4/configure.ac    2026-07-23 03:42:56.000000000 +0200
+++ new/tcpreplay-4.5.5/configure.ac    2026-07-24 02:18:57.000000000 +0200
@@ -4,7 +4,7 @@
 AC_PREREQ([2.69])
 
 dnl Set version info here!
-AC_INIT([tcpreplay],[4.5.4],[https://github.com/appneta/tcpreplay/issues],[tcpreplay],[http://tcpreplay.sourceforge.net/])
+AC_INIT([tcpreplay],[4.5.5],[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)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/docs/CHANGELOG 
new/tcpreplay-4.5.5/docs/CHANGELOG
--- old/tcpreplay-4.5.4/docs/CHANGELOG  2026-07-23 03:42:56.000000000 +0200
+++ new/tcpreplay-4.5.5/docs/CHANGELOG  2026-07-24 02:24:11.000000000 +0200
@@ -1,3 +1,65 @@
+07/23/2026 Version 4.5.5
+    - SECURITY: fix heap buffer over-read in get_layer4_v6() 
(GHSA-jj65-mrgg-f5fx, CWE-125).
+      get_ipv6_next() (src/common/get.c) validates the header it is given, but 
the pointer it
+      returns is only checked with "ptr > end_ptr" - so it may be exactly 
end_ptr, or leave
+      fewer bytes than a tcpr_ipv6_ext_hdr_base needs. get_layer4_v6() then 
read ip_nh straight
+      off that pointer, one byte past the packet buffer, for a crafted IPv6 
packet whose
+      extension header chain runs to the end of the captured data. Reachable 
from tcpprep,
+      tcprewrite and tcpreplay when reading an untrusted pcap. A bounds check 
is now applied at
+      the three sites that dereference such a pointer. This was reported in 
2024 against 4.4.4
+      and marked patched, but the reporter's proof-of-concept still reproduced 
on 4.5.4.
+      Reported by msxfXF.
+    - SECURITY: fix stack buffer overflow in the fragroute rules-file parser
+      (GHSA-777w-9599-w8g4, CWE-787). On a successful parse, mod_open()
+      (src/fragroute/mod.c) accumulated a "<mod> -> <mod> -> ..." diagnostic 
of every parsed
+      rule into a BUFSIZ (8192) local, then copied it into the caller's errbuf 
with an
+      unbounded sprintf(); callers size errbuf at FRAGROUTE_ERRBUF_LEN (1024), 
so a rules file
+      with a few hundred valid one-word directives overflowed a stack buffer 
in an ancestor
+      frame (tcprewrite's main()) by several kilobytes, before any packet was 
processed. The
+      message was written only on the success path, where errbuf is never 
read, so the whole
+      diagnostic has been removed; the remaining errbuf writes in mod_open() 
are now bounded
+      with snprintf(). Reported by tinyb0y.
+    - SECURITY: fix out-of-bounds write on an empty fragroute rules file
+      (GHSA-p7xp-4gj2-x56c, CWE-787, CWE-191). The same removed diagnostic 
trimmed its trailing
+      " -> " with buf[strlen(buf) - 4] = '\0'. A rules file that parsed 
cleanly but produced no
+      rules (empty, or only comments and blank lines) left buf empty, so the 
index underflowed
+      size_t and wrote before the start of the buffer. Found while reviewing
+      GHSA-777w-9599-w8g4; fixed by the same removal.
+    - SECURITY: fix off-by-one heap buffer overflow in the fragroute ip_chaff 
module
+      (GHSA-m655-53p4-6qm8, CWE-193, CWE-787). ip_chaff_apply()
+      (src/fragroute/mod_ip_chaff.c) called rand_strset() with (pkt_end - 
pkt_ip_data + 1),
+      writing one byte past the end of the allocation pkt_dup() had just made; 
the call
+      precedes the subtype switch, so it ran for every ip_chaff invocation 
(dup, opt, or a
+      numeric TTL) on any ordinary IP packet. Also fixed in the same path: 
pkt_dup()
+      (src/fragroute/pkt.c) never initialized the duplicate's pkt_buf_size, 
which ip_chaff's
+      opt subtype then passed to ip_add_option() as a capacity bound, and its 
out-of-memory
+      path freed the *source* packet - still linked in the caller's pktq - 
with free() rather
+      than releasing the half-built duplicate with the matching brel(). 
Reported by tinyb0y.
+    - SECURITY: fix off-by-one heap buffer overflow in the fragroute tcp_chaff 
module
+      (GHSA-v8c4-9w98-9v6v, CWE-193, CWE-787). tcp_chaff_apply()
+      (src/fragroute/mod_tcp_chaff.c) had the identical defect in the sibling 
module that
+      GHSA-m655-53p4-6qm8 covers, calling rand_strset() with (pkt_end - 
pkt_tcp_data + 1).
+      Triggered by any tcp_chaff directive against an ordinary TCP packet. 
Found while
+      auditing the ip_chaff fix.
+    - SECURITY: fix heap buffer overflow via negative fragment/segment size in 
the fragroute
+      ip_frag and tcp_seg modules (GHSA-27v4-xhfx-g2rx, CWE-787, CWE-190). 
Both modules parsed
+      their size argument with strtol() and rejected only zero; ip_frag's 
"must be a multiple
+      of 8" check also passed negative multiples (-8 % 8 == 0 in C). A 
negative size then
+      defeated the "does this fragment fit" guard (a signed comparison against 
a positive
+      ptrdiff_t) and reached memcpy() as a huge implicitly-converted size_t, in
+      ip_frag_apply_ipv4(), ip_frag_apply_ipv6() and tcp_seg_apply(). Both 
modules now require
+      1..IP_LEN_MAX at rules-file parse time, which also rejects strtol() 
overflow truncating
+      to a negative int. Reported by tinyb0y.
+    - fragroute: check pkt_new()/pkt_dup() for failure in the ip_frag, tcp_seg 
and tcp_chaff
+      modules. Six call sites dereferenced the returned packet immediately, so 
an allocation
+      failure crashed on a NULL pointer instead of aborting the rule.
+    - fragroute: don't free a rule that is still linked into the rule list. 
mod_open()'s
+      cleanup freed its last-allocated rule unconditionally; this was harmless 
only because
+      the removed success-path diagnostic left the variable NULL, and would 
otherwise have
+      left a dangling entry for mod_apply() to walk on every packet.
+    - test: add fragroute test cases (fragroute_valid, fragroute_negsize, 
fragroute_badrules)
+      covering the modules above; previously the fragroute tree had no test 
coverage at all.
+
 07/22/2026 Version 4.5.4
     - SECURITY: fix heap buffer overflow in the tcprewrite fragroute tcp_opt 
module
       (GHSA-pfqg-243f-8q25, CWE-787, CVSS 8.4). tcp_opt_apply() 
(src/fragroute/mod_tcp_opt.c)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/docs/CREDIT 
new/tcpreplay-4.5.5/docs/CREDIT
--- old/tcpreplay-4.5.4/docs/CREDIT     2026-07-23 03:42:56.000000000 +0200
+++ new/tcpreplay-4.5.5/docs/CREDIT     2026-07-24 02:24:11.000000000 +0200
@@ -162,9 +162,18 @@
     - tcprewrite: fix vlan tag add silently truncating output when 
--enet-vlan-pri/-cfi omitted (#994)
     - tcpprep: fix buffer overflow in check_dst_port() on truncated L4 headers 
(#995)
 
+msxfXF <GitHub @msxfXF>
+    - common: reported heap buffer over-read in get_layer4_v6() when walking 
IPv6
+      extension headers (GHSA-jj65-mrgg-f5fx)
+
 tinyb0y <GitHub @tinyb0y>
     - fragroute: reported heap buffer overflow in tcp_opt module 
(GHSA-pfqg-243f-8q25)
     - fragroute: reported heap buffer overflow in ip6_opt module 
(GHSA-2wmf-4p77-784q)
+    - fragroute: reported stack buffer overflow in the rules-file parser 
(GHSA-777w-9599-w8g4)
+    - fragroute: reported off-by-one heap buffer overflow in ip_chaff module
+      (GHSA-m655-53p4-6qm8)
+    - fragroute: reported heap buffer overflow via negative fragment/segment 
size in the
+      ip_frag and tcp_seg modules (GHSA-27v4-xhfx-g2rx)
 
 jiezhuzzz <GitHub @jiezhuzzz>
     - tcpedit: reported and proposed fix for SEGV in DLT_JUNIPER_ETHER plugin 
when used as
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/common/get.c 
new/tcpreplay-4.5.5/src/common/get.c
--- old/tcpreplay-4.5.4/src/common/get.c        2026-07-23 02:49:35.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/common/get.c        2026-07-24 02:24:11.000000000 
+0200
@@ -624,6 +624,20 @@
     return ((void *)ptr);
 }
 
+/*
+ * Is a complete extension-header base (ip_nh + ip_len) readable at hdr?
+ *
+ * get_ipv6_next() only guarantees that the pointer it returns is not past
+ * end_ptr - it may be exactly end_ptr, or leave fewer bytes than the base
+ * header needs. Any caller that dereferences that pointer has to check first,
+ * or it reads off the end of the packet buffer.
+ */
+static inline bool
+ipv6_exthdr_fits(const struct tcpr_ipv6_ext_hdr_base *hdr, const u_char 
*end_ptr)
+{
+    return hdr != NULL && (const u_char *)hdr + sizeof(*hdr) <= end_ptr;
+}
+
 /**
  * returns a pointer to the layer 4 header which is just beyond the IPv6 header
  * and any extension headers or NULL when there is none as in the case of
@@ -662,7 +676,7 @@
         case TCPR_IPV6_NH_HBH:
             dbgx(3, "Going deeper due to extension header 0x%02X", proto);
             exthdr = get_ipv6_next(next, end_ptr);
-            if (exthdr == NULL) {
+            if (!ipv6_exthdr_fits(exthdr, end_ptr)) {
                 next = NULL;
                 done = true;
                 break;
@@ -678,7 +692,7 @@
             // next points to l4 data
             dbgx(3, "Go deeper due to fragment extension header 0x%02X", 
proto);
             exthdr = get_ipv6_next(next, end_ptr);
-            if ((exthdr == NULL) || ((u_char *)exthdr > end_ptr)) {
+            if (!ipv6_exthdr_fits(exthdr, end_ptr)) {
                 next = NULL;
                 done = true;
                 break;
@@ -701,6 +715,11 @@
          */
         default:
             if (proto != ip6_hdr->ip_nh && next) {
+                /* reading next->ip_len needs the base header to be present */
+                if (!ipv6_exthdr_fits(next, end_ptr)) {
+                    return NULL;
+                }
+
                 dbgx(3, "Returning byte offset of this ext header: %u", 
IPV6_EXTLEN_TO_BYTES(next->ip_len));
                 next = (void *)((u_char *)next + 
IPV6_EXTLEN_TO_BYTES(next->ip_len));
                 if ((u_char*)next > end_ptr)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/common/git_version.c 
new/tcpreplay-4.5.5/src/common/git_version.c
--- old/tcpreplay-4.5.4/src/common/git_version.c        2026-07-23 
03:54:30.000000000 +0200
+++ new/tcpreplay-4.5.5/src/common/git_version.c        2026-07-24 
02:48:39.000000000 +0200
@@ -1,4 +1,4 @@
-const char GIT_Version[] = "git:v4.5.4";
+const char GIT_Version[] = "git:v4.5.5-3-g3737e9da";
 const char *git_version(void) {
     return GIT_Version;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/fragroute/mod.c 
new/tcpreplay-4.5.5/src/fragroute/mod.c
--- old/tcpreplay-4.5.4/src/fragroute/mod.c     2026-07-17 19:54:49.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/fragroute/mod.c     2026-07-24 02:16:36.000000000 
+0200
@@ -13,6 +13,9 @@
 #include "config.h"
 #include "common.h"
 #include "argv.h"
+
+/* for FRAGROUTE_ERRBUF_LEN, the size callers give errbuf */
+#include "fragroute.h"
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -89,7 +92,7 @@
 
     /* open the config/script file */
     if ((fp = fopen(script, "r")) == NULL) {
-        sprintf(errbuf, "couldn't open %s", script);
+        snprintf(errbuf, FRAGROUTE_ERRBUF_LEN, "couldn't open %s", script);
         return (-1);
     }
     dbg(1, "opened config file...");
@@ -101,7 +104,7 @@
 
         /* parse the line into an array */
         if ((argc = argv_create(buf, MAX_ARGS, argv)) < 1) {
-            sprintf(errbuf, "couldn't parse arguments (line %d)", i);
+            snprintf(errbuf, FRAGROUTE_ERRBUF_LEN, "couldn't parse arguments 
(line %d)", i);
             ret = -1;
             break;
         }
@@ -117,14 +120,14 @@
 
         /* do we have a match? */
         if (*m == NULL) {
-            sprintf(errbuf, "unknown directive '%s' (line %d)", argv[0], i);
+            snprintf(errbuf, FRAGROUTE_ERRBUF_LEN, "unknown directive '%s' 
(line %d)", argv[0], i);
             ret = -1;
             break;
         }
 
         /* allocate memory for our rule */
         if ((rule = calloc(1, sizeof(*rule))) == NULL) {
-            sprintf(errbuf, "calloc");
+            snprintf(errbuf, FRAGROUTE_ERRBUF_LEN, "calloc");
             ret = -1;
             break;
         }
@@ -132,29 +135,35 @@
 
         /* pass the remaining args to the rule */
         if (rule->mod->open != NULL && (rule->data = rule->mod->open(argc, 
argv)) == NULL) {
-            sprintf(errbuf, "invalid argument to directive '%s' (line %d)", 
rule->mod->name, i);
+            snprintf(errbuf, FRAGROUTE_ERRBUF_LEN, "invalid argument to 
directive '%s' (line %d)", rule->mod->name, i);
             ret = -1;
             break;
         }
         /* append the rule to the rule list */
         TAILQ_INSERT_TAIL(&rules, rule, next);
+
+        /*
+         * The rule now belongs to the list; drop our reference so the orphan
+         * cleanup below can't free a rule that mod_apply() still walks.
+         */
+        rule = NULL;
     }
 
     /* close the file */
     fclose(fp);
     dbg(1, "close file...");
 
-    if (ret == 0) {
-        buf[0] = '\0';
-        TAILQ_FOREACH(rule, &rules, next)
-        {
-            strlcat(buf, rule->mod->name, sizeof(buf));
-            strlcat(buf, " -> ", sizeof(buf));
-        }
-        buf[strlen(buf) - 4] = '\0';
-        sprintf(errbuf, "wtf: %s", buf);
-    }
+    /*
+     * No success-path message is written to errbuf: it is only read when we
+     * return < 0.  The former "wtf: <rule list>" diagnostic built the list in
+     * a BUFSIZ (8192) local and sprintf()'d it into errbuf, which callers size
+     * at FRAGROUTE_ERRBUF_LEN (1024) - a rules file with enough directives
+     * overflowed the caller's stack buffer.  It also indexed 
buf[strlen(buf)-4]
+     * to trim the trailing " -> ", underflowing when the file parsed cleanly
+     * but produced no rules (empty or comment-only).
+     */
 
+    /* free a rule that was allocated but never made it onto the list */
     if (rule)
         free(rule);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/fragroute/mod_ip_chaff.c 
new/tcpreplay-4.5.5/src/fragroute/mod_ip_chaff.c
--- old/tcpreplay-4.5.4/src/fragroute/mod_ip_chaff.c    2025-07-28 
01:54:42.000000000 +0200
+++ new/tcpreplay-4.5.5/src/fragroute/mod_ip_chaff.c    2026-07-24 
02:16:36.000000000 +0200
@@ -77,8 +77,16 @@
         if (pkt->pkt_ip_data == NULL)
             continue;
 
-        new = pkt_dup(pkt);
-        rand_strset(data->rnd, new->pkt_ip_data, new->pkt_end - 
new->pkt_ip_data + 1);
+        if ((new = pkt_dup(pkt)) == NULL) {
+            return -1;
+        }
+
+        /*
+         * Fill only the bytes the duplicate actually owns.  The span is
+         * [pkt_ip_data, pkt_end), so the old "+ 1" wrote one byte past the
+         * end of the allocation pkt_dup() just made.
+         */
+        rand_strset(data->rnd, new->pkt_ip_data, new->pkt_end - 
new->pkt_ip_data);
 
         switch (data->type) {
         case CHAFF_TYPE_DUP:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/fragroute/mod_ip_frag.c 
new/tcpreplay-4.5.5/src/fragroute/mod_ip_frag.c
--- old/tcpreplay-4.5.4/src/fragroute/mod_ip_frag.c     2025-07-28 
01:54:42.000000000 +0200
+++ new/tcpreplay-4.5.5/src/fragroute/mod_ip_frag.c     2026-07-24 
02:16:36.000000000 +0200
@@ -54,7 +54,16 @@
     ip_frag_data.rnd = rand_open();
     ip_frag_data.size = (int)strtol(argv[1], NULL, 10);
 
-    if (ip_frag_data.size == 0 || (ip_frag_data.size % 8) != 0) {
+    /*
+     * Reject non-positive sizes explicitly: a negative multiple of 8 passes
+     * the "% 8" test (-8 % 8 == 0 in C) and reaches memcpy() as a huge
+     * implicitly-converted size_t.
+     */
+    if (ip_frag_data.size <= 0 || ip_frag_data.size > IP_LEN_MAX) {
+        warn("fragment size must be between 1 and 65535 bytes");
+        return (ip_frag_close(&ip_frag_data));
+    }
+    if ((ip_frag_data.size % 8) != 0) {
         warn("fragment size must be a multiple of 8");
         return (ip_frag_close(&ip_frag_data));
     }
@@ -132,7 +141,10 @@
             continue;
 
         for (p = pkt->pkt_ip_data; p < pkt->pkt_end;) {
-            new = pkt_new(pkt->pkt_buf_size);
+            if ((new = pkt_new(pkt->pkt_buf_size)) == NULL) {
+                return -1;
+            }
+
             memcpy(new->pkt_eth, pkt->pkt_eth, (u_char *)pkt->pkt_eth_data - 
(u_char *)pkt->pkt_eth);
             memcpy(new->pkt_ip, pkt->pkt_ip, hl);
             new->pkt_ip_data = new->pkt_eth_data + hl;
@@ -166,7 +178,10 @@
             TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
 
             if (p2 != NULL) {
-                new = pkt_dup(new);
+                if ((new = pkt_dup(new)) == NULL) {
+                    return -1;
+                }
+
                 new->pkt_ts.tv_usec = 1;
                 new->pkt_ip->ip_off = htons(IP_MF | off);
                 new->pkt_ip->ip_len = htons(hl + (fraglen << 1));
@@ -235,7 +250,10 @@
         next_hdr = pkt->pkt_ip6->ip6_nxt;
 
         for (p = pkt->pkt_ip_data; p < pkt->pkt_end;) {
-            new = pkt_new(pkt->pkt_buf_size);
+            if ((new = pkt_new(pkt->pkt_buf_size)) == NULL) {
+                return -1;
+            }
+
             memcpy(new->pkt_eth, pkt->pkt_eth, (u_char *)pkt->pkt_eth_data - 
(u_char *)pkt->pkt_eth);
             memcpy(new->pkt_ip, pkt->pkt_ip, hl);
             ext = (struct ip6_ext_hdr *)((u_char *)new->pkt_eth_data + hl);
@@ -274,7 +292,10 @@
             TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
 
             if (p2 != NULL) {
-                new = pkt_dup(new);
+                if ((new = pkt_dup(new)) == NULL) {
+                    return -1;
+                }
+
                 new->pkt_ts.tv_usec = 1;
 
                 ext->ext_data.fragment.offlg = htons(off << 3) | IP6_MORE_FRAG;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/fragroute/mod_tcp_chaff.c 
new/tcpreplay-4.5.5/src/fragroute/mod_tcp_chaff.c
--- old/tcpreplay-4.5.4/src/fragroute/mod_tcp_chaff.c   2025-07-28 
01:54:42.000000000 +0200
+++ new/tcpreplay-4.5.5/src/fragroute/mod_tcp_chaff.c   2026-07-24 
02:16:36.000000000 +0200
@@ -103,8 +103,16 @@
             (pkt->pkt_tcp->th_flags & TH_ACK) == 0)
             continue;
 
-        new = pkt_dup(pkt);
-        rand_strset(data->rnd, new->pkt_tcp_data, new->pkt_end - 
new->pkt_tcp_data + 1);
+        if ((new = pkt_dup(pkt)) == NULL) {
+            return -1;
+        }
+
+        /*
+         * Fill only the bytes the duplicate actually owns.  The span is
+         * [pkt_tcp_data, pkt_end), so the old "+ 1" wrote one byte past the
+         * end of the allocation pkt_dup() just made.
+         */
+        rand_strset(data->rnd, new->pkt_tcp_data, new->pkt_end - 
new->pkt_tcp_data);
 
         switch (data->type) {
         case CHAFF_TYPE_CKSUM:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/fragroute/mod_tcp_seg.c 
new/tcpreplay-4.5.5/src/fragroute/mod_tcp_seg.c
--- old/tcpreplay-4.5.4/src/fragroute/mod_tcp_seg.c     2025-07-28 
01:54:42.000000000 +0200
+++ new/tcpreplay-4.5.5/src/fragroute/mod_tcp_seg.c     2026-07-24 
02:16:36.000000000 +0200
@@ -49,8 +49,13 @@
     }
     tcp_seg_data.rnd = rand_open();
 
-    if ((tcp_seg_data.size = (int)strtol(argv[1], NULL, 10)) == 0) {
-        warnx("invalid segment size '%s'", argv[1]);
+    /*
+     * A negative size survives as a negative int, then reaches memcpy() as a
+     * huge implicitly-converted size_t (and walks the segment loop backwards).
+     */
+    tcp_seg_data.size = (int)strtol(argv[1], NULL, 10);
+    if (tcp_seg_data.size <= 0 || tcp_seg_data.size > IP_LEN_MAX) {
+        warnx("invalid segment size '%s' (must be between 1 and 65535 bytes)", 
argv[1]);
         return (tcp_seg_close(&tcp_seg_data));
     }
     if (argc == 3) {
@@ -109,7 +114,10 @@
         for (p = pkt->pkt_tcp_data; p < pkt->pkt_end; p += len) {
             u_char *p1, *p2;
 
-            new = pkt_new(pkt->pkt_buf_size);
+            if ((new = pkt_new(pkt->pkt_buf_size)) == NULL) {
+                return -1;
+            }
+
             memcpy(new->pkt_eth, pkt->pkt_eth, (u_char *)pkt->pkt_eth_data - 
(u_char *)pkt->pkt_eth);
             p1 = p, p2 = NULL;
             len = MIN(pkt->pkt_end - p, tcp_seg_data.size);
@@ -150,7 +158,10 @@
             TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
 
             if (p2 != NULL) {
-                new = pkt_dup(new);
+                if ((new = pkt_dup(new)) == NULL) {
+                    return -1;
+                }
+
                 new->pkt_ts.tv_usec = 1;
                 if (eth_type == ETH_TYPE_IP) {
                     new->pkt_ip->ip_id = rand_uint16(tcp_seg_data.rnd);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/fragroute/pkt.c 
new/tcpreplay-4.5.5/src/fragroute/pkt.c
--- old/tcpreplay-4.5.4/src/fragroute/pkt.c     2025-07-28 01:54:42.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/fragroute/pkt.c     2026-07-24 02:16:36.000000000 
+0200
@@ -45,7 +45,8 @@
     pkt->pkt_buf_size = PKT_BUF_ALIGN + len;
     pkt->pkt_buf = malloc(max((size_t)PKT_BUF_LEN, pkt->pkt_buf_size));
     if (pkt->pkt_buf == NULL) {
-        free(pkt);
+        /* pkt came from bget(), so it must go back via brel(), not free() */
+        brel(pkt);
         return NULL;
     }
 
@@ -70,10 +71,18 @@
 
     new->pkt_buf = malloc(pkt->pkt_buf_size);
     if (new->pkt_buf == NULL) {
-        free(pkt);
+        /*
+         * Release the half-built duplicate, not the source packet: pkt is
+         * still linked into the caller's pktq, and it came from bget(), so
+         * free() was both the wrong object and the wrong allocator.
+         */
+        brel(new);
         return NULL;
     }
 
+    /* the duplicate owns an allocation of its own; record its size */
+    new->pkt_buf_size = pkt->pkt_buf_size;
+
     off = new->pkt_buf - pkt->pkt_buf;
 
     new->pkt_ts = pkt->pkt_ts;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpbridge.1 
new/tcpreplay-4.5.5/src/tcpbridge.1
--- old/tcpreplay-4.5.4/src/tcpbridge.1 2026-07-23 03:53:03.000000000 +0200
+++ new/tcpreplay-4.5.5/src/tcpbridge.1 2026-07-24 02:48:24.000000000 +0200
@@ -10,12 +10,12 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpbridge 1 "22 Jul 2026" "tcpbridge" "User Commands"
+.TH tcpbridge 1 "23 Jul 2026" "tcpbridge" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"
 .\" It has been AutoGen-ed
-.\" From the definitions ../../src/tcpbridge_opts.def
+.\" From the definitions tcpbridge_opts.def
 .\" and the template file agman-cmd.tpl
 .SH NAME
 \f\*[B-Font]tcpbridge\fP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpbridge_opts.c 
new/tcpreplay-4.5.5/src/tcpbridge_opts.c
--- old/tcpreplay-4.5.4/src/tcpbridge_opts.c    2026-07-23 03:52:47.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpbridge_opts.c    2026-07-24 02:47:41.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpbridge_opts.c)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpbridge_opts.def
+ *  From the definitions    tcpbridge_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpbridge_opts.h 
new/tcpreplay-4.5.5/src/tcpbridge_opts.h
--- old/tcpreplay-4.5.4/src/tcpbridge_opts.h    2026-07-23 03:52:47.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpbridge_opts.h    2026-07-24 02:47:41.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpbridge_opts.h)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpbridge_opts.def
+ *  From the definitions    tcpbridge_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpcapinfo.1 
new/tcpreplay-4.5.5/src/tcpcapinfo.1
--- old/tcpreplay-4.5.4/src/tcpcapinfo.1        2026-07-23 03:53:02.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpcapinfo.1        2026-07-24 02:48:23.000000000 
+0200
@@ -10,12 +10,12 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpcapinfo 1 "22 Jul 2026" "Tcpreplay Suite" "User Commands"
+.TH tcpcapinfo 1 "23 Jul 2026" "Tcpreplay Suite" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"
 .\" It has been AutoGen-ed
-.\" From the definitions ../../src/tcpcapinfo_opts.def
+.\" From the definitions tcpcapinfo_opts.def
 .\" and the template file agman-cmd.tpl
 .SH NAME
 \f\*[B-Font]tcpcapinfo\fP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpcapinfo_opts.c 
new/tcpreplay-4.5.5/src/tcpcapinfo_opts.c
--- old/tcpreplay-4.5.4/src/tcpcapinfo_opts.c   2026-07-23 03:52:45.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpcapinfo_opts.c   2026-07-24 02:47:37.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpcapinfo_opts.c)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpcapinfo_opts.def
+ *  From the definitions    tcpcapinfo_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpcapinfo_opts.h 
new/tcpreplay-4.5.5/src/tcpcapinfo_opts.h
--- old/tcpreplay-4.5.4/src/tcpcapinfo_opts.h   2026-07-23 03:52:45.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpcapinfo_opts.h   2026-07-24 02:47:37.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpcapinfo_opts.h)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpcapinfo_opts.def
+ *  From the definitions    tcpcapinfo_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpedit/tcpedit_stub.h 
new/tcpreplay-4.5.5/src/tcpedit/tcpedit_stub.h
--- old/tcpreplay-4.5.4/src/tcpedit/tcpedit_stub.h      2026-07-23 
03:52:50.000000000 +0200
+++ new/tcpreplay-4.5.5/src/tcpedit/tcpedit_stub.h      2026-07-24 
02:47:49.000000000 +0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpedit_stub.h)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../../src/tcpedit/tcpedit_stub.def
+ *  From the definitions    tcpedit_stub.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpliveplay.1 
new/tcpreplay-4.5.5/src/tcpliveplay.1
--- old/tcpreplay-4.5.4/src/tcpliveplay.1       2026-07-23 03:53:04.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpliveplay.1       2026-07-22 07:40:43.000000000 
+0200
@@ -1,132 +1,133 @@
-.de1 NOP
-.  it 1 an-trap
-.  if \\n[.$] \,\\$*\/
-..
-.ie t \
-.ds B-Font [CB]
-.ds I-Font [CI]
-.ds R-Font [CR]
-.el \
-.ds B-Font B
-.ds I-Font I
-.ds R-Font R
-.TH tcpliveplay 1 "22 Jul 2026" "tcpliveplay" "User Commands"
-.\"
-.\" DO NOT EDIT THIS FILE (in-mem file)
+'\" t
+.\"     Title: tcpliveplay
+.\"    Author: [see the "AUTHOR(S)" section]
+.\" Generator: Asciidoctor 2.0.23
+.\"      Date: 2026-07-21
+.\"    Manual: Tcpreplay Suite
+.\"    Source: Tcpreplay Suite
+.\"  Language: English
 .\"
-.\" It has been AutoGen-ed
-.\" From the definitions ../../src/tcpliveplay_opts.def
-.\" and the template file agman-cmd.tpl
-.SH NAME
-\f\*[B-Font]tcpliveplay\fP
-\- Replays network traffic stored in a pcap file on live networks using new 
TCP connections
-.SH SYNOPSIS
-\f\*[B-Font]tcpliveplay\fP
-.\" Mixture of short (flag) options and long options
-[\f\*[B-Font]\-flags\f[]]
-[\f\*[B-Font]\-flag\f[] [\f\*[I-Font]value\f[]]]
-[\f\*[B-Font]\-\-option-name\f[][[=| ]\f\*[I-Font]value\f[]]]
-<eth0/eth1> <file.pcap> <Destination IP [1.2.3.4]> <Destination mac 
[0a:1b:2c:3d:4e:5f]> <'random' dst port OR specify dport #>
-.sp \n(Ppu
-.ne 2
-
-This program, 'tcpliveplay' replays a captured set of packets using new TCP
-connections with the captured TCP payloads against a remote host in order to
-do comprehensive vulnerability testing.
+.TH "TCPLIVEPLAY" "1" "2026-07-21" "Tcpreplay Suite" "Tcpreplay Suite"
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.ss \n[.ss] 0
+.nh
+.ad l
+.de URL
+\fI\\$2\fP <\\$1>\\$3
+..
+.als MTO URL
+.if \n[.g] \{\
+.  mso www.tmac
+.  am URL
+.    ad l
+.  .
+.  am MTO
+.    ad l
+.  .
+.  LINKSTYLE blue R < >
+.\}
+.SH "NAME"
+tcpliveplay \- Replays network traffic stored in a pcap file on live networks 
using new TCP connections
+.SH "SYNOPSIS"
+.sp
+\fBtcpliveplay\fP [\fIOPTION\fP]... <eth0/eth1> <file.pcap> <Destination IP 
[1.2.3.4]> <Destination mac [0a:1b:2c:3d:4e:5f]> <\*(Aqrandom\*(Aq dst port OR 
specify dport #>
 .SH "DESCRIPTION"
-The basic operation of tcpliveplay is it rewrites the given pcap file
-in a scheduled event format and responds with the appropriate packet if
-the remote host meets tcp protocal's SEQ/ACK expectation. Once expectations
-are met, then the local packets are sent with the same payload except with
-new tcp SEQ & ACK numbers meeting the response from the remote hose.
-.sp
-The input pcap file are rewritten to start at the first encounter of the
-SYN packet for correct operation making this packet be the first action in
-the event schedule of local host doing the replay.
 .sp
-For more details, please see the Tcpreplay Manual at:
-http://tcpreplay.appneta.com
+This program, \*(Aqtcpliveplay\*(Aq replays a captured set of packets using 
new TCP connections with the captured TCP payloads against a remote host in 
order to do comprehensive vulnerability testing.
+.sp
+The basic operation of tcpliveplay is it rewrites the given pcap file in a 
scheduled event format and responds with the appropriate packet if the remote 
host meets tcp protocal\(cqs SEQ/ACK expectation. Once expectations are met, 
then the local packets are sent with the same payload except with new tcp SEQ & 
ACK numbers meeting the response from the remote hose.
+.sp
+The input pcap file are rewritten to start at the first encounter of the SYN 
packet for correct operation making this packet be the first action in the 
event schedule of local host doing the replay.
+.sp
+For more details, please see the Tcpreplay Manual at: \c
+.URL "http://tcpreplay.appneta.com"; "" ""
 .SH "OPTIONS"
-.TP
-.NOP \f\*[B-Font]\-d\f[] \f\*[I-Font]number\f[], 
\f\*[B-Font]\-\-dbug\f[]=\f\*[I-Font]number\f[]
-Enable debugging output.
-This option may appear up to 1 times.
-This option takes an integer number as its argument.
-The value of
-\f\*[I-Font]number\f[]
-is constrained to being:
-.in +4
-.nf
-.na
-in the range  0 through 5
-.fi
-.in -4
-The default
-\f\*[I-Font]number\f[]
-for this option is:
-.ti +4
- 0
-.sp
-If configured with \--enable-debug, then you can specify a verbosity
-level for debugging output.  Higher numbers increase verbosity.
-.TP
-.NOP \f\*[B-Font]\-V\f[], \f\*[B-Font]\-\-version\f[]
+.sp
+\fB\-d\fP, \fB\-\-dbug\fP=\fInumber\fP
+.RS 4
+Enable debugging output. Range: 0 to 5. Default: \f(CR0\fP.
+.sp
+If configured with \-\-enable\-debug, then you can specify a verbosity level 
for debugging output.  Higher numbers increase verbosity.
+.RE
+.sp
+\fB\-V\fP, \fB\-\-version\fP
+.RS 4
 Print version information.
+.RE
 .sp
-.TP
-.NOP \f\*[B-Font]\-h\f[], \f\*[B-Font]\-\-less\-help\f[]
+\fB\-h\fP, \fB\-\-less\-help\fP
+.RS 4
 Display less usage information and exit.
+.RE
 .sp
-.TP
-.NOP \f\*[B-Font]\-H\f[], \f\*[B-Font]\-\-help\f[]
+\fB\-H\fP, \fB\-\-help\fP
+.RS 4
 Display usage information and exit.
-.TP
-.NOP \f\*[B-Font]\-\&!\f[], \f\*[B-Font]\-\-more-help\f[]
+.RE
+.sp
+\fB\-\-more\-help\fP
+.RS 4
 Pass the extended usage information through a pager.
-.TP
-.NOP \f\*[B-Font]\-\-save-opts\f[] [=\f\*[I-Font]cfgfile\f[]]
-Save the option state to \fIcfgfile\fP.  The default is the \fIlast\fP
-configuration file listed in the \fBOPTION PRESETS\fP section, below.
-The command will exit after updating the config file.
-.TP
-.NOP \f\*[B-Font]\-\-load-opts\f[]=\f\*[I-Font]cfgfile\f[], 
\f\*[B-Font]\-\-no-load-opts\f[]
-Load options from \fIcfgfile\fP.
-The \fIno-load-opts\fP form will disable the loading
-of earlier config/rc/ini files.  \fI\-\-no-load-opts\fP is handled early,
-out of order.
-.PP
+.RE
+.sp
+\fB\-\-save\-opts\fP[=\fIstring\fP]
+.RS 4
+Save the current option state to a config file.
+.RE
+.sp
+\fB\-\-load\-opts\fP=\fIstring\fP, \fB\-\-no\-load\-opts\fP
+.RS 4
+Load options from a config file; \fB\-\-no\-load\-opts\fP disables this.
+.RE
 .SH "OPTION PRESETS"
-Any option that is not marked as \fInot presettable\fP may be preset
-by loading values from configuration ("RC" or ".INI") file(s).
-The \fIhomerc\fP file is "\fI$$/\fP", unless that is a directory.
-In that case, the file "\fI.tcpliveplayrc\fP"
-is searched for within that directory.
+.sp
+Any option that is not marked as \fInot presettable\fP may be preset by 
loading values from configuration ("RC" or ".INI") file(s).
+The homerc file is \fI$$/\fP, unless that is a directory; in that case 
\fI.tcpliveplayrc\fP is searched for within it.
 .SH "FILES"
+.sp
 See \fBOPTION PRESETS\fP for configuration files.
 .SH "EXIT STATUS"
+.sp
 One of the following exit values will be returned:
-.TP
-.NOP 0 " (EXIT_SUCCESS)"
+.sp
+\fB0\fP (EXIT_SUCCESS)
+.RS 4
 Successful program execution.
-.TP
-.NOP 1 " (EXIT_FAILURE)"
+.RE
+.sp
+\fB1\fP (EXIT_FAILURE)
+.RS 4
 The operation failed or the command syntax was not valid.
-.TP
-.NOP 66 " (EX_NOINPUT)"
+.RE
+.sp
+\fB66\fP (EX_NOINPUT)
+.RS 4
 A specified configuration file could not be loaded.
-.TP
-.NOP 70 " (EX_SOFTWARE)"
-libopts had an internal operational error.  Please report
-it to [email protected].  Thank you.
-.PP
+.RE
+.sp
+\fB70\fP (EX_SOFTWARE)
+.RS 4
+libopts had an internal operational error. Please report it to \c
+.MTO "autogen\-users\(atlists.sourceforge.net" "" "."
+Thank you.
+.RE
 .SH "AUTHORS"
+.sp
 Copyright 2012 Yazan Siam
-For support please use the [email protected] mailing list.
-The latest version of this software is always available from:
-http://tcpreplay.appneta.com
+.sp
+For support please use the \c
+.MTO "tcpreplay\-users\(atlists.sourceforge.net" "" ""
+mailing list.
+.sp
+The latest version of this software is always available from: \c
+.URL "http://tcpreplay.appneta.com"; "" ""
 .SH "COPYRIGHT"
-Copyright (C) 2012 Yazan Siam all rights reserved.
-This program is released under the terms of the Modified Berkeley Software 
Distribution License.
+.sp
+This program is released under the Modified (3 clause) Berkeley Software 
Distribution License.
+.SH "BUGS"
+.sp
+Please send bug reports through the project\(cqs issue tracker.
 .SH "NOTES"
-This manual page was \fIAutoGen\fP-erated from the \fBtcpliveplay\fP
-option definitions.
+.sp
+This manual page was generated from the tcpliveplay option definitions.
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpliveplay_opts.c 
new/tcpreplay-4.5.5/src/tcpliveplay_opts.c
--- old/tcpreplay-4.5.4/src/tcpliveplay_opts.c  2026-07-23 03:52:43.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpliveplay_opts.c  2026-07-22 07:32:17.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpliveplay_opts.c)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpliveplay_opts.def
+ *  From the definitions    tcpliveplay_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpliveplay_opts.h 
new/tcpreplay-4.5.5/src/tcpliveplay_opts.h
--- old/tcpreplay-4.5.4/src/tcpliveplay_opts.h  2026-07-23 03:52:43.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpliveplay_opts.h  2026-07-22 07:32:11.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpliveplay_opts.h)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpliveplay_opts.def
+ *  From the definitions    tcpliveplay_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpprep.1 
new/tcpreplay-4.5.5/src/tcpprep.1
--- old/tcpreplay-4.5.4/src/tcpprep.1   2026-07-23 03:52:59.000000000 +0200
+++ new/tcpreplay-4.5.5/src/tcpprep.1   2026-07-24 02:48:18.000000000 +0200
@@ -10,12 +10,12 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpprep 1 "22 Jul 2026" "tcpprep" "User Commands"
+.TH tcpprep 1 "23 Jul 2026" "tcpprep" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"
 .\" It has been AutoGen-ed
-.\" From the definitions ../../src/tcpprep_opts.def
+.\" From the definitions tcpprep_opts.def
 .\" and the template file agman-cmd.tpl
 .SH NAME
 \f\*[B-Font]tcpprep\fP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpprep_opts.c 
new/tcpreplay-4.5.5/src/tcpprep_opts.c
--- old/tcpreplay-4.5.4/src/tcpprep_opts.c      2026-07-23 03:52:46.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpprep_opts.c      2026-07-24 02:47:38.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpprep_opts.c)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpprep_opts.def
+ *  From the definitions    tcpprep_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpprep_opts.h 
new/tcpreplay-4.5.5/src/tcpprep_opts.h
--- old/tcpreplay-4.5.4/src/tcpprep_opts.h      2026-07-23 03:52:46.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpprep_opts.h      2026-07-24 02:47:38.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpprep_opts.h)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpprep_opts.def
+ *  From the definitions    tcpprep_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpreplay-edit.1 
new/tcpreplay-4.5.5/src/tcpreplay-edit.1
--- old/tcpreplay-4.5.4/src/tcpreplay-edit.1    2026-07-23 03:53:01.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpreplay-edit.1    2026-07-24 02:48:21.000000000 
+0200
@@ -10,12 +10,12 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpreplay-edit 1 "22 Jul 2026" "tcpreplay" "User Commands"
+.TH tcpreplay-edit 1 "23 Jul 2026" "tcpreplay" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"
 .\" It has been AutoGen-ed
-.\" From the definitions ../../src/tcpreplay_opts.def
+.\" From the definitions tcpreplay_opts.def
 .\" and the template file agman-cmd.tpl
 .SH NAME
 \f\*[B-Font]tcpreplay-edit\fP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpreplay.1 
new/tcpreplay-4.5.5/src/tcpreplay.1
--- old/tcpreplay-4.5.4/src/tcpreplay.1 2026-07-23 03:52:58.000000000 +0200
+++ new/tcpreplay-4.5.5/src/tcpreplay.1 2026-07-24 02:48:16.000000000 +0200
@@ -10,12 +10,12 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpreplay 1 "22 Jul 2026" "tcpreplay" "User Commands"
+.TH tcpreplay 1 "23 Jul 2026" "tcpreplay" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"
 .\" It has been AutoGen-ed
-.\" From the definitions ../../src/tcpreplay_opts.def
+.\" From the definitions tcpreplay_opts.def
 .\" and the template file agman-cmd.tpl
 .SH NAME
 \f\*[B-Font]tcpreplay\fP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpreplay_edit_opts.c 
new/tcpreplay-4.5.5/src/tcpreplay_edit_opts.c
--- old/tcpreplay-4.5.4/src/tcpreplay_edit_opts.c       2026-07-23 
03:52:40.000000000 +0200
+++ new/tcpreplay-4.5.5/src/tcpreplay_edit_opts.c       2026-07-24 
02:47:29.000000000 +0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpreplay_edit_opts.c)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpreplay_opts.def
+ *  From the definitions    tcpreplay_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpreplay_edit_opts.h 
new/tcpreplay-4.5.5/src/tcpreplay_edit_opts.h
--- old/tcpreplay-4.5.4/src/tcpreplay_edit_opts.h       2026-07-23 
03:52:40.000000000 +0200
+++ new/tcpreplay-4.5.5/src/tcpreplay_edit_opts.h       2026-07-24 
02:47:29.000000000 +0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpreplay_edit_opts.h)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpreplay_opts.def
+ *  From the definitions    tcpreplay_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpreplay_opts.c 
new/tcpreplay-4.5.5/src/tcpreplay_opts.c
--- old/tcpreplay-4.5.4/src/tcpreplay_opts.c    2026-07-23 03:52:41.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpreplay_opts.c    2026-07-24 02:47:32.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpreplay_opts.c)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpreplay_opts.def
+ *  From the definitions    tcpreplay_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcpreplay_opts.h 
new/tcpreplay-4.5.5/src/tcpreplay_opts.h
--- old/tcpreplay-4.5.4/src/tcpreplay_opts.h    2026-07-23 03:52:41.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcpreplay_opts.h    2026-07-24 02:47:32.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcpreplay_opts.h)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcpreplay_opts.def
+ *  From the definitions    tcpreplay_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcprewrite.1 
new/tcpreplay-4.5.5/src/tcprewrite.1
--- old/tcpreplay-4.5.4/src/tcprewrite.1        2026-07-23 03:53:00.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcprewrite.1        2026-07-24 02:48:20.000000000 
+0200
@@ -10,12 +10,12 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcprewrite 1 "22 Jul 2026" "tcprewrite" "User Commands"
+.TH tcprewrite 1 "23 Jul 2026" "tcprewrite" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"
 .\" It has been AutoGen-ed
-.\" From the definitions ../../src/tcprewrite_opts.def
+.\" From the definitions tcprewrite_opts.def
 .\" and the template file agman-cmd.tpl
 .SH NAME
 \f\*[B-Font]tcprewrite\fP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcprewrite_opts.c 
new/tcpreplay-4.5.5/src/tcprewrite_opts.c
--- old/tcpreplay-4.5.4/src/tcprewrite_opts.c   2026-07-23 03:52:44.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcprewrite_opts.c   2026-07-24 02:47:34.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcprewrite_opts.c)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcprewrite_opts.def
+ *  From the definitions    tcprewrite_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/src/tcprewrite_opts.h 
new/tcpreplay-4.5.5/src/tcprewrite_opts.h
--- old/tcpreplay-4.5.4/src/tcprewrite_opts.h   2026-07-23 03:52:44.000000000 
+0200
+++ new/tcpreplay-4.5.5/src/tcprewrite_opts.h   2026-07-24 02:47:34.000000000 
+0200
@@ -3,7 +3,7 @@
  *  DO NOT EDIT THIS FILE   (tcprewrite_opts.h)
  *
  *  It has been AutoGen-ed
- *  From the definitions    ../../src/tcprewrite_opts.def
+ *  From the definitions    tcprewrite_opts.def
  *  and the template file   options
  *
  * Generated from AutoOpts 42:1:17 templates.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/test/Makefile.am 
new/tcpreplay-4.5.5/test/Makefile.am
--- old/tcpreplay-4.5.4/test/Makefile.am        2026-07-23 02:49:35.000000000 
+0200
+++ new/tcpreplay-4.5.5/test/Makefile.am        2026-07-24 02:18:57.000000000 
+0200
@@ -16,7 +16,18 @@
 
 TEST_PCAP=$(srcdir)/test.pcap
 
-EXTRA_DIST = test.pcap test.auto_bridge test.auto_client test.auto_router \
+# IP-only capture for the fragroute tests: fragroute aborts on the first
+# non-IP packet, and test.pcap contains plenty of those.
+FRAGROUTE_PCAP=$(srcdir)/test_fragroute.pcap
+
+if COMPILE_FRAGROUTE
+FRAGROUTE_TESTS = fragroute_valid fragroute_negsize fragroute_badrules
+else
+FRAGROUTE_TESTS =
+endif
+
+EXTRA_DIST = test.pcap test_fragroute.pcap \
+               test.auto_bridge test.auto_client test.auto_router \
                test.auto_server test.auto_first test.cidr test.comment 
test.port test.mac \
                test.cidr_reverse test.mac_reverse test.regex_reverse \
                test.include_packets test.exclude_packets test.include_source \
@@ -216,7 +227,8 @@
        rewrite_1ttl rewrite_2ttl rewrite_3ttl rewrite_1ttl-hdrfix 
rewrite_2ttl-hdrfix rewrite_3ttl-hdrfix \
        rewrite_tos rewrite_mtutrunc rewrite_enet_subsmac rewrite_mac_seed \
        rewrite_mac_seed_keep rewrite_l7fuzzing rewrite_sequence 
rewrite_fixcsum \
-       rewrite_fixlen_pad rewrite_fixlen_trunc rewrite_fixlen_del
+       rewrite_fixlen_pad rewrite_fixlen_trunc rewrite_fixlen_del \
+       $(FRAGROUTE_TESTS)
 
 tcpreplay: replay_basic replay_nano_timer replay_cache replay_pps replay_rate 
replay_top \
        replay_config replay_multi replay_pps_multi replay_precache \
@@ -884,8 +896,102 @@
            $(PRINTF) "\t\t\t%s\n" "FAILED"; od -Ax -tx1 -v test.$@1 >> 
test.log; false; \
        fi
 
+if COMPILE_FRAGROUTE
+# fragroute embeds random IP IDs and fills chaff packets with random bytes, so
+# its output is not reproducible run to run and there is no golden file to diff
+# against. These check exit status instead, and specifically distinguish a
+# clean rejection from a crash: tcprewrite exits 255 on a fatal error, while a
+# status of 128..254 means the shell saw it die from a signal (SIGSEGV is 139,
+# SIGABRT 134), which is what the memory-safety bugs in these modules looked
+# like.
+#
+# Note what fragroute_valid can and cannot catch. In an ordinary build it only
+# proves that valid rules still parse, run and produce output - the one-byte
+# heap overflows fixed in ip_chaff and tcp_chaff do not crash an unsanitized
+# binary, so this target passes against the buggy code. Configure with
+# --enable-asan to make those regressions fail here; the other two targets
+# catch their bugs (SIGSEGV) in a plain build.
+
+fragroute_valid:
+       $(PRINTF) "%s" "[tcprewrite] Fragroute valid rules test: "
+       $(PRINTF) "%s\n" "*** [tcprewrite] Fragroute valid rules test: " >> 
test.log
+       rc=0; \
+       for rule in "ip_frag 8" "ip_frag 16 old" "ip_frag 8 new" "tcp_seg 8" \
+                   "tcp_seg 16 old" "ip_chaff dup" "ip_chaff opt" "tcp_chaff 
cksum" \
+                   "tcp_chaff null" "dup random 100" "order random" "ip_ttl 
5"; do \
+           $(PRINTF) "%s\n" "$$rule" > [email protected]; \
+           $(PRINTF) "%s\n" "--- $$rule" >> test.log; \
+           $(TCPREWRITE) $(ENABLE_DEBUG) [email protected] \
+               -i $(FRAGROUTE_PCAP) -o test.$@1 >> test.log 2>&1; \
+           status=$$?; \
+           if [ $$status -ne 0 ]; then \
+               $(PRINTF) "%s\n" "ERROR: '$$rule' exited $$status" >> test.log; 
rc=1; \
+           elif [ ! -s test.$@1 ]; then \
+               $(PRINTF) "%s\n" "ERROR: '$$rule' produced no output" >> 
test.log; rc=1; \
+           fi; \
+       done; \
+       if [ $$rc -eq 0 ]; then \
+           $(PRINTF) "\t\t%s\n" "OK"; \
+       else \
+           $(PRINTF) "\t\t%s\n" "FAILED"; false; \
+       fi
+
+# A negative fragment/segment size used to pass validation (-8 % 8 == 0) and
+# reach memcpy() as a huge size_t. It must be refused at parse time, and the
+# refusal must not be a crash.
+fragroute_negsize:
+       $(PRINTF) "%s" "[tcprewrite] Fragroute negative size test: "
+       $(PRINTF) "%s\n" "*** [tcprewrite] Fragroute negative size test: " >> 
test.log
+       rc=0; \
+       for rule in "ip_frag -8" "ip_frag -16" "ip_frag 0" "tcp_seg -8" 
"tcp_seg 0"; do \
+           $(PRINTF) "%s\n" "$$rule" > [email protected]; \
+           $(PRINTF) "%s\n" "--- $$rule" >> test.log; \
+           $(TCPREWRITE) $(ENABLE_DEBUG) [email protected] \
+               -i $(FRAGROUTE_PCAP) -o test.$@1 > [email protected] 2>&1; \
+           status=$$?; \
+           cat [email protected] >> test.log; \
+           if [ $$status -eq 0 ]; then \
+               $(PRINTF) "%s\n" "ERROR: '$$rule' was accepted" >> test.log; 
rc=1; \
+           elif [ $$status -ge 128 ] && [ $$status -le 254 ]; then \
+               $(PRINTF) "%s\n" "ERROR: '$$rule' died from signal $$(($$status 
- 128))" >> test.log; rc=1; \
+           elif ! grep -q "must be between 1 and 65535" [email protected]; then \
+               $(PRINTF) "%s\n" "ERROR: '$$rule' failed, but not by rejecting 
the size" >> test.log; rc=1; \
+           fi; \
+       done; \
+       if [ $$rc -eq 0 ]; then \
+           $(PRINTF) "\t\t%s\n" "OK"; \
+       else \
+           $(PRINTF) "\t\t%s\n" "FAILED"; false; \
+       fi
+
+# Rules files that are degenerate but not invalid: many directives used to
+# overflow the caller's error buffer, and a file with no rules at all used to
+# index buf[strlen(buf) - 4]. Both must parse and run normally.
+fragroute_badrules:
+       $(PRINTF) "%s" "[tcprewrite] Fragroute degenerate rules test: "
+       $(PRINTF) "%s\n" "*** [tcprewrite] Fragroute degenerate rules test: " 
>> test.log
+       rc=0; \
+       : > [email protected]; \
+       $(PRINTF) "%s\n" "# nothing but a comment" > [email protected]; \
+       awk 'BEGIN { for (i = 0; i < 300; i++) print "print" }' > 
[email protected]; \
+       for f in empty comment many; do \
+           $(PRINTF) "%s\n" "--- $$f rules" >> test.log; \
+           $(TCPREWRITE) $(ENABLE_DEBUG) --fragroute=test.$@.$$f.rules \
+               -i $(FRAGROUTE_PCAP) -o test.$@1 >> test.log 2>&1; \
+           status=$$?; \
+           if [ $$status -ne 0 ]; then \
+               $(PRINTF) "%s\n" "ERROR: $$f rules exited $$status" >> 
test.log; rc=1; \
+           fi; \
+       done; \
+       if [ $$rc -eq 0 ]; then \
+           $(PRINTF) "\t\t%s\n" "OK"; \
+       else \
+           $(PRINTF) "\t\t%s\n" "FAILED"; false; \
+       fi
+endif
+
 clean:
-       rm -f *1 test.log core* *~ primary.data secondary.data
+       rm -f *1 test.log core* *~ primary.data secondary.data *.rules *.out
 
 distclean: clean
        rm -f Makefile Makefile.in config
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tcpreplay-4.5.4/test/Makefile.in 
new/tcpreplay-4.5.5/test/Makefile.in
--- old/tcpreplay-4.5.4/test/Makefile.in        2026-07-23 03:52:24.000000000 
+0200
+++ new/tcpreplay-4.5.5/test/Makefile.in        2026-07-24 02:46:46.000000000 
+0200
@@ -314,7 +314,14 @@
 TCPREWRITE = ../src/tcprewrite
 TCPBRIDGE = ../src/tcpbridge
 TEST_PCAP = $(srcdir)/test.pcap
-EXTRA_DIST = test.pcap test.auto_bridge test.auto_client test.auto_router \
+
+# IP-only capture for the fragroute tests: fragroute aborts on the first
+# non-IP packet, and test.pcap contains plenty of those.
+FRAGROUTE_PCAP = $(srcdir)/test_fragroute.pcap
+@COMPILE_FRAGROUTE_FALSE@FRAGROUTE_TESTS = 
+@COMPILE_FRAGROUTE_TRUE@FRAGROUTE_TESTS = fragroute_valid fragroute_negsize 
fragroute_badrules
+EXTRA_DIST = test.pcap test_fragroute.pcap \
+               test.auto_bridge test.auto_client test.auto_router \
                test.auto_server test.auto_first test.cidr test.comment 
test.port test.mac \
                test.cidr_reverse test.mac_reverse test.regex_reverse \
                test.include_packets test.exclude_packets test.include_source \
@@ -700,7 +707,8 @@
        rewrite_1ttl rewrite_2ttl rewrite_3ttl rewrite_1ttl-hdrfix 
rewrite_2ttl-hdrfix rewrite_3ttl-hdrfix \
        rewrite_tos rewrite_mtutrunc rewrite_enet_subsmac rewrite_mac_seed \
        rewrite_mac_seed_keep rewrite_l7fuzzing rewrite_sequence 
rewrite_fixcsum \
-       rewrite_fixlen_pad rewrite_fixlen_trunc rewrite_fixlen_del
+       rewrite_fixlen_pad rewrite_fixlen_trunc rewrite_fixlen_del \
+       $(FRAGROUTE_TESTS)
 
 tcpreplay: replay_basic replay_nano_timer replay_cache replay_pps replay_rate 
replay_top \
        replay_config replay_multi replay_pps_multi replay_precache \
@@ -1366,8 +1374,100 @@
            $(PRINTF) "\t\t\t%s\n" "FAILED"; od -Ax -tx1 -v test.$@1 >> 
test.log; false; \
        fi
 
+# fragroute embeds random IP IDs and fills chaff packets with random bytes, so
+# its output is not reproducible run to run and there is no golden file to diff
+# against. These check exit status instead, and specifically distinguish a
+# clean rejection from a crash: tcprewrite exits 255 on a fatal error, while a
+# status of 128..254 means the shell saw it die from a signal (SIGSEGV is 139,
+# SIGABRT 134), which is what the memory-safety bugs in these modules looked
+# like.
+#
+# Note what fragroute_valid can and cannot catch. In an ordinary build it only
+# proves that valid rules still parse, run and produce output - the one-byte
+# heap overflows fixed in ip_chaff and tcp_chaff do not crash an unsanitized
+# binary, so this target passes against the buggy code. Configure with
+# --enable-asan to make those regressions fail here; the other two targets
+# catch their bugs (SIGSEGV) in a plain build.
+
+@COMPILE_FRAGROUTE_TRUE@fragroute_valid:
+@COMPILE_FRAGROUTE_TRUE@       $(PRINTF) "%s" "[tcprewrite] Fragroute valid 
rules test: "
+@COMPILE_FRAGROUTE_TRUE@       $(PRINTF) "%s\n" "*** [tcprewrite] Fragroute 
valid rules test: " >> test.log
+@COMPILE_FRAGROUTE_TRUE@       rc=0; \
+@COMPILE_FRAGROUTE_TRUE@       for rule in "ip_frag 8" "ip_frag 16 old" 
"ip_frag 8 new" "tcp_seg 8" \
+@COMPILE_FRAGROUTE_TRUE@                   "tcp_seg 16 old" "ip_chaff dup" 
"ip_chaff opt" "tcp_chaff cksum" \
+@COMPILE_FRAGROUTE_TRUE@                   "tcp_chaff null" "dup random 100" 
"order random" "ip_ttl 5"; do \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "%s\n" "$$rule" > [email protected]; \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "%s\n" "--- $$rule" >> test.log; \
+@COMPILE_FRAGROUTE_TRUE@           $(TCPREWRITE) $(ENABLE_DEBUG) 
[email protected] \
+@COMPILE_FRAGROUTE_TRUE@               -i $(FRAGROUTE_PCAP) -o test.$@1 >> 
test.log 2>&1; \
+@COMPILE_FRAGROUTE_TRUE@           status=$$?; \
+@COMPILE_FRAGROUTE_TRUE@           if [ $$status -ne 0 ]; then \
+@COMPILE_FRAGROUTE_TRUE@               $(PRINTF) "%s\n" "ERROR: '$$rule' 
exited $$status" >> test.log; rc=1; \
+@COMPILE_FRAGROUTE_TRUE@           elif [ ! -s test.$@1 ]; then \
+@COMPILE_FRAGROUTE_TRUE@               $(PRINTF) "%s\n" "ERROR: '$$rule' 
produced no output" >> test.log; rc=1; \
+@COMPILE_FRAGROUTE_TRUE@           fi; \
+@COMPILE_FRAGROUTE_TRUE@       done; \
+@COMPILE_FRAGROUTE_TRUE@       if [ $$rc -eq 0 ]; then \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "\t\t%s\n" "OK"; \
+@COMPILE_FRAGROUTE_TRUE@       else \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "\t\t%s\n" "FAILED"; false; \
+@COMPILE_FRAGROUTE_TRUE@       fi
+
+# A negative fragment/segment size used to pass validation (-8 % 8 == 0) and
+# reach memcpy() as a huge size_t. It must be refused at parse time, and the
+# refusal must not be a crash.
+@COMPILE_FRAGROUTE_TRUE@fragroute_negsize:
+@COMPILE_FRAGROUTE_TRUE@       $(PRINTF) "%s" "[tcprewrite] Fragroute negative 
size test: "
+@COMPILE_FRAGROUTE_TRUE@       $(PRINTF) "%s\n" "*** [tcprewrite] Fragroute 
negative size test: " >> test.log
+@COMPILE_FRAGROUTE_TRUE@       rc=0; \
+@COMPILE_FRAGROUTE_TRUE@       for rule in "ip_frag -8" "ip_frag -16" "ip_frag 
0" "tcp_seg -8" "tcp_seg 0"; do \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "%s\n" "$$rule" > [email protected]; \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "%s\n" "--- $$rule" >> test.log; \
+@COMPILE_FRAGROUTE_TRUE@           $(TCPREWRITE) $(ENABLE_DEBUG) 
[email protected] \
+@COMPILE_FRAGROUTE_TRUE@               -i $(FRAGROUTE_PCAP) -o test.$@1 > 
[email protected] 2>&1; \
+@COMPILE_FRAGROUTE_TRUE@           status=$$?; \
+@COMPILE_FRAGROUTE_TRUE@           cat [email protected] >> test.log; \
+@COMPILE_FRAGROUTE_TRUE@           if [ $$status -eq 0 ]; then \
+@COMPILE_FRAGROUTE_TRUE@               $(PRINTF) "%s\n" "ERROR: '$$rule' was 
accepted" >> test.log; rc=1; \
+@COMPILE_FRAGROUTE_TRUE@           elif [ $$status -ge 128 ] && [ $$status -le 
254 ]; then \
+@COMPILE_FRAGROUTE_TRUE@               $(PRINTF) "%s\n" "ERROR: '$$rule' died 
from signal $$(($$status - 128))" >> test.log; rc=1; \
+@COMPILE_FRAGROUTE_TRUE@           elif ! grep -q "must be between 1 and 
65535" [email protected]; then \
+@COMPILE_FRAGROUTE_TRUE@               $(PRINTF) "%s\n" "ERROR: '$$rule' 
failed, but not by rejecting the size" >> test.log; rc=1; \
+@COMPILE_FRAGROUTE_TRUE@           fi; \
+@COMPILE_FRAGROUTE_TRUE@       done; \
+@COMPILE_FRAGROUTE_TRUE@       if [ $$rc -eq 0 ]; then \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "\t\t%s\n" "OK"; \
+@COMPILE_FRAGROUTE_TRUE@       else \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "\t\t%s\n" "FAILED"; false; \
+@COMPILE_FRAGROUTE_TRUE@       fi
+
+# Rules files that are degenerate but not invalid: many directives used to
+# overflow the caller's error buffer, and a file with no rules at all used to
+# index buf[strlen(buf) - 4]. Both must parse and run normally.
+@COMPILE_FRAGROUTE_TRUE@fragroute_badrules:
+@COMPILE_FRAGROUTE_TRUE@       $(PRINTF) "%s" "[tcprewrite] Fragroute 
degenerate rules test: "
+@COMPILE_FRAGROUTE_TRUE@       $(PRINTF) "%s\n" "*** [tcprewrite] Fragroute 
degenerate rules test: " >> test.log
+@COMPILE_FRAGROUTE_TRUE@       rc=0; \
+@COMPILE_FRAGROUTE_TRUE@       : > [email protected]; \
+@COMPILE_FRAGROUTE_TRUE@       $(PRINTF) "%s\n" "# nothing but a comment" > 
[email protected]; \
+@COMPILE_FRAGROUTE_TRUE@       awk 'BEGIN { for (i = 0; i < 300; i++) print 
"print" }' > [email protected]; \
+@COMPILE_FRAGROUTE_TRUE@       for f in empty comment many; do \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "%s\n" "--- $$f rules" >> 
test.log; \
+@COMPILE_FRAGROUTE_TRUE@           $(TCPREWRITE) $(ENABLE_DEBUG) 
--fragroute=test.$@.$$f.rules \
+@COMPILE_FRAGROUTE_TRUE@               -i $(FRAGROUTE_PCAP) -o test.$@1 >> 
test.log 2>&1; \
+@COMPILE_FRAGROUTE_TRUE@           status=$$?; \
+@COMPILE_FRAGROUTE_TRUE@           if [ $$status -ne 0 ]; then \
+@COMPILE_FRAGROUTE_TRUE@               $(PRINTF) "%s\n" "ERROR: $$f rules 
exited $$status" >> test.log; rc=1; \
+@COMPILE_FRAGROUTE_TRUE@           fi; \
+@COMPILE_FRAGROUTE_TRUE@       done; \
+@COMPILE_FRAGROUTE_TRUE@       if [ $$rc -eq 0 ]; then \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "\t\t%s\n" "OK"; \
+@COMPILE_FRAGROUTE_TRUE@       else \
+@COMPILE_FRAGROUTE_TRUE@           $(PRINTF) "\t\t%s\n" "FAILED"; false; \
+@COMPILE_FRAGROUTE_TRUE@       fi
+
 clean:
-       rm -f *1 test.log core* *~ primary.data secondary.data
+       rm -f *1 test.log core* *~ primary.data secondary.data *.rules *.out
 
 distclean: clean
        rm -f Makefile Makefile.in config
Binary files old/tcpreplay-4.5.4/test/test_fragroute.pcap and 
new/tcpreplay-4.5.5/test/test_fragroute.pcap differ

Reply via email to