Skip to content

Releases: appneta/tcpreplay

v4.6.1

Choose a tag to compare

@fklassen fklassen released this 15 Aug 00:41
v4.6.1
0196d0c

Tcpreplay 4.6.1 is a security and hardening release. Its centerpiece is a new continuous fuzzing pipeline — three libFuzzer targets covering the pcap parser, the fragroute rules engine, and the tcpprep --services parser, submitted to OSS-Fuzz — which found and fixed nine defects in its first days running, on top of three new GHSA security advisories reported directly and a round of UBSan/ASan hardening across the packet parsers.

Highlights

  • Continuous fuzzing via OSS-Fuzz — three new libFuzzer targets (fuzz_pcap, fuzz_fragroute, fuzz_services) run continuously against every commit; this release fixes all nine issues they found in their first run, from a heap-buffer-overflow write to a resource-exhaustion hang
  • 3 new security advisories fixed, two of them CVSS 7.0+ (High)
  • UBSan now runs alongside ASan in CI, catching a class of misaligned-access bugs that ASan alone doesn't — the fix also made wire-format header structs packed, removing systemic misaligned access across the packet parsers
  • --xdp-batch-size removed — measurement on 100GigE found no benefit from raising it above the default of 1, now that AF_XDP sends pipeline across the whole umem (from 4.6.0)

Security

Three new advisories, all reported by tao pan (@pant0m):

Advisory CVSS Severity Component
GHSA-4hqm-8v2c-9pwj 7.1 High Three heap out-of-bounds reads in tcpliveplay's pcap parsing — one can leak adjacent heap memory onto the live network
GHSA-pmmx-m8p5-969j 7.0 High Inverted bounds check in the dlt_radiotap plugin — an 8-year-old >=/<= typo that made an oversized memcpy() run exactly when it was guaranteed to overflow. Not reachable through the bundled CLIs, which clamp caplen; only third-party code linking libtcpedit directly on unclamped input is affected
GHSA-p3f2-88rg-9mch 6.1 Medium Heap out-of-bounds read in tcpprep cache-file parsing — the file's packets_per_byte field was never cross-checked against the hardcoded indexing stride every reader actually uses

Continuous fuzzing: nine issues found and fixed

This cycle added test/fuzz/ — three libFuzzer targets built against ASan/UBSan and submitted to OSS-Fuzz (#1092, #1101, #1103). Every issue below was found by that pipeline before it ever reached a user, and none had a public GitHub issue filed for it (#1118) — they're listed here for the first time now that fixes are shipped.

Finding Crash type Fix
ip_chaff_apply() heap-buffer-overflow write 2-byte OOB write A buffer-capacity calculation assumed the IP header started 2 bytes earlier than it actually does (missing a PKT_BUF_ALIGN offset), overstating room by exactly 2 bytes — libdnet wrote an inserted IP option 2 bytes past the heap allocation
ip_chaff_apply() pointer corruption → OOB read Out-of-bounds read The option-insert path used libdnet's return value unconditionally, including on failure, silently shifting a packet pointer out of bounds on every failed call; a rules file stacking several ip_chaff opt directives could walk it far enough to underflow a length calculation downstream
mod_apply() exponential packet growth Timeout (>60s) Duplicating rules (ip_chaff, tcp_chaff) double the packet queue on every application; stacking ~30 of them in a rules file turns one packet into gigabytes of output. Now bounded at a hard packet-count cap between rule applications
mod_close() never called Direct memory leak A fully-implemented cleanup function that freed the whole parsed rule chain was never wired up — leaked on every fragroute_close() call, not just in fuzzing
rand_t leak in ip_frag/tcp_seg Direct memory leak Both modules store their RNG handle in a file-scope static rather than per-rule heap state; a repeated directive overwrote the handle without closing the previous one
pktq_shuffle() on an empty queue Unexpected exit An empty-queue edge case was misdiagnosed as an allocation failure and called exit()
get_l2len_protocol() on an unsupported DLT Unexpected exit The one error path in the function that called exit() instead of returning an error code, like every other branch
raw_ip_opt_parse() too-few-tokens Null dereference A tcp_opt raw rule with one fewer token than ip_opt raw needs slipped past a caller-side length check and read past the token array
delay_apply() on an empty queue Null dereference Same empty-queue class as pktq_shuffle() above, in a different module

Other fixes

  • UBSan hardening: fixed misaligned MPLS label parsing and a negative left shift in fragroute's ip_ttl; wire-format header structs are now packed, fixing systemic misaligned access flagged once UBSan ran in CI (#1100, #1104)
  • fragroute: fixed a use-after-free in pkt_close() on repeated context setup (#1102)
  • txring: fixed TX_RING failing outright on interfaces with an MTU of ~1365 or less, e.g. 1280, the IPv6 minimum (#1090)
  • common: fixed an out-of-bounds write from an undersized struct bpf_program stub on HAVE_LIBBPF builds, hit by tcpprep/tcpbridge's -f option (#1121)
  • fragroute: fixed an uninitialized-stack read in mod_open()'s debug logging — an intermittent crash under --dbug (#1124)
  • tcpedit: fixed 17 -Waddress-of-packed-member warnings left by the packed-struct fix above (#1122)
  • test: added a dependency-free unit test suite under test/unit, run by make check and ctest (#1079)
  • build: minor compilation fixes and warning cleanups found while building with meson warning_level=3 (#1116, contributed by @GabrielGanne)

Credits

Thanks to tao pan (@pant0m) for the three security reports behind this release, and to @GabrielGanne for compilation cleanups. The remaining nine fixes came from the new OSS-Fuzz pipeline this release also introduces.

What's Changed

  • xdp: remove --xdp-batch-size — measurement on 100GigE found no benefit from raising it above the default of 1 (#1128)
  • tcpedit: fix 17 -Waddress-of-packed-member warnings left by the packed-struct fix (#1122, #1127)
  • common: fix out-of-bounds write from an undersized struct bpf_program stub on HAVE_LIBBPF builds (#1121, #1125)
  • fragroute: fix uninitialized-stack read in mod_open()'s debug logging under --dbug (#1124)
  • fix: flow_decode() over-required bytes for a minimal ICMP/ICMPv6 header (#1119, #1120)
  • fix(fuzz): don't auto-file public GitHub issues from OSS-Fuzz findings (#1092, #1118)
  • fix(fuzz): build a minimal libpcap for OSS-Fuzz targets instead of linking the system one (#1092, #1117)
  • ci: run UBSan alongside ASan; mark wire-format header structs packed (#1101, #1104, #1105, #1112)
  • test: add libFuzzer targets for the pcap, fragroute rules, and tcpprep --services parsers; submit to OSS-Fuzz (#1092, #1103, #1113, #1114, #1115)
  • txring: fix TX_RING failing outright on interfaces with an MTU of ~1365 or less (#1090, #1107, #1109, #1111)
  • test: add a dependency-free unit test suite under test/unit, run by make check/ctest (#1079, #1091, #1099, #1106)
  • fragroute: fix a use-after-free in pkt_close() on repeated context setup (#1102)
  • build: minor compilation fixes and warning cleanups found building with meson warning_level=3 (#1116)
  • Security: fix inverted bounds check in dlt_radiotap_get_80211()GHSA-pmmx-m8p5-969j (#1141)
  • Security: fix three heap OOB reads in tcpliveplay's pcap parsing — GHSA-4hqm-8v2c-9pwj (#1140)
  • Security: reject cache files whose packets_per_byte doesn't match the hardcoded indexing stride — GHSA-p3f2-88rg-9mch (#1139)
  • fragroute: bound mod_apply() against exponential packet-count growth (OSS-Fuzz 546146015, #1138)
  • fragroute: fix a rand_t leak in ip_frag_open()/tcp_seg_open() on a repeated directive (OSS-Fuzz 545925322, #1137)
  • fragroute: wire up mod_close(), implemented but never called (OSS-Fuzz 545818605, #1136)
  • fragroute: fix a null-deref in delay_apply() on an empty packet queue (OSS-Fuzz 545965632, #1135)
  • fragroute: fix a null-deref in raw_ip_opt_parse() on a tcp_opt raw rule with too few tokens (OSS-Fuzz 545904184, #1134)
  • fragroute: fix pointer corruption in ip_chaff_apply() on a failed option insert (OSS-Fuzz 545925319, #1133)
  • fragroute: fix a heap-buffer-overflow in ip_chaff_apply()'s option insertion (OSS-Fuzz 545965630, #1132)
  • common: fix an Unexpected-exit in get_l2len_protocol() on an unsupported DLT type (OSS-Fuzz 545718476, #1131)
  • fragroute: fix an Unexpected-exit in pktq_shuffle() on an empty packet queue (OSS-Fuzz 545904182, #1130)

Verifying the download

The .tar.gz/.tar.xz tarballs are accompanied by detached PGP signatures (.asc), signed with the tcpreplay release key (tcpreplay@appneta.com, fingerprint 84E4FA215C934A7D97DC76D5E9E2149793BDE17E):

gpg --verify tcpreplay-4.6.1.tar.xz.asc tcpreplay-4.6.1.tar.xz

Full Changelog: v4.6.0...v4.6.1

v4.6.0

Choose a tag to compare

@fklassen fklassen released this 28 Jul 00:31

Tcpreplay 4.6.0 is a major release built around three things: a new CMake build system, two high-throughput packet-injection backends that now genuinely reach line rate, and a set of security fixes on top of 4.5.5. It also folds in a correctness pass on the TX_RING send path, several new CLI features, and a jumbo-frame bug that had been silently truncating packets.

Highlights

  • Completely updated documentation sitetcpreplay.appneta.com now has a modern, task-oriented guide: installation, quickstart, performance testing, fast-path backends, and a reference page per tool
  • CMake build, alongside the existing autotools flow (cmake -B build && cmake --build build)
  • AF_XDP (--xdp) now reaches line rate on 1GigE — from an initial ~13k pps to ~305k pps (941 Mbps) on commodity e1000 hardware, ahead of the default injector
  • io_uring (--io-uring) batches sends instead of one syscall per packet — ~11% less CPU per packet
  • --raw — a new PF_INET/SOCK_RAW injection path that sends through the local IP stack
  • --loss — random percent packet-loss simulation for testing against non-ideal network conditions
  • 3 new security advisories fixed on top of 4.5.5
  • Jumbo frames fixed — a long-standing bug truncated any frame beyond an MTU that needed more than one page of ring buffer to a flat 4096 bytes
  • TX_RING reliability fixed — the default Linux send path could silently drop and reorder packets; both are now fixed

New features

Feature Flag Notes
io_uring injection --io-uring Async submission via Linux io_uring; portable to any modern kernel
AF_XDP injection --xdp Kernel-bypass via an XDP socket; falls back automatically if the adapter can't support it
— queue selection --xdp-queue Bind to a specific adapter queue instead of always queue 0
— strict mode --xdp-no-fallback Fail rather than silently fall back — for benchmarking, where a silent change of injector would change what's measured
— batch tuning --xdp-batch-size For very high-speed links (100GigE+) with small packets; not normally needed
Raw IP socket injection --raw Routes through the kernel's IP stack (routing, netfilter); IPv4-only, rebuilds L2 framing
Packet-loss simulation --loss Independently drops each packet at a given 0–100% probability (contributed by @dsseng)
Raw IP (L3-only) interfaces Replay onto WireGuard/tun-style interfaces with no L2 header
Static library libtcpreplay The replay engine is now installable as a standalone C library
CMake build Full feature parity with autotools; every --enable-*/--with-* has a CMake equivalent

Performance: getting AF_XDP to actually earn its name

--xdp was close to unusable in practice — it worked on some adapters and not others, occasionally hung, and where it did run, underperformed the default injector by orders of magnitude. Chasing that down turned up four separate, compounding bugs:

  1. No attach-mode fallback. AF_XDP socket setup never told the kernel which mode to bind in, so it silently required native driver XDP support — absent on e1000, e1000e, and plenty of other common adapters — with no fallback to generic (SKB) mode.
  2. Unbounded hangs. Two send-path loops retried forever with no timeout, so a driver that accepted the socket but never actually transmitted wedged the whole replay in an unkillable 100% CPU spin.
  3. A ring descriptor leak in --xdp-batch-size. Reserved-but-unused TX descriptors were never returned, so any batch size that didn't evenly divide the pcap's packet count caused throughput to collapse — measured as low as 120 pps.
  4. No pipelining. The send path indexed its packet buffer modulo the batch size, so it had to block until an entire batch fully completed before it could prepare the next one — a full TX completion round-trip per packet.

With all four fixed — plus a --loop bug that desynced the ring after the first pass and wedged, --xdp-queue, and the auto-fallback above — a real-world before/after on a 1GigE e1000:

pps throughput
--xdp, before this work 13,344 41 Mbps
--xdp, fully fixed 305,168 941 Mbps
default injector (TX_RING), for reference 242,979 749 Mbps

That's a 23× improvement, and AF_XDP now saturates a 1GigE link where the default injector doesn't.

io_uring got a smaller but genuine fix along the way: it previously issued one io_uring_enter() syscall per packet — no better than a plain send() loop — plus extra bookkeeping on top, so it was slower than not using it at all. Submissions now batch 64 deep with strict in-order delivery, cutting syscall count 64× for roughly 11% less CPU per packet.

Reliability and correctness fixes

  • TX_RING was silently dropping and reordering packets (the default Linux send path). It filled ring frames out of order, which both misordered packets on the wire and permanently stranded any frame the kernel hadn't finished with — discarded at teardown after already being counted as successfully sent. In the worst case, a short replay reported 100% of packets sent while transmitting none. Fixed by filling the ring strictly in order and draining it before statistics are read.
  • Jumbo frames truncated to 4096 bytes. A block-sizing bug in the TX_RING setup divided the frame size back down to a single page after correctly growing the block to fit the MTU, silently mangling any capture with frames larger than ~4KB.
  • --xdp hung indefinitely rather than failing when AF_XDP couldn't be used, and returned success on some fatal send errors, hiding failures from CI and scripts.
  • Assorted build-system correctness fixes: configure.ac could enable AF_XDP support from a bare link test without the matching headers, producing a build that failed partway through; cached CMake feature probes could report a library missing after it had since been installed, with no indication a re-probe was needed.

Security

Three new advisories are fixed beyond 4.5.5, all reported by tinyb0y:

Advisory Severity Component
GHSA-fwcr-mqg6-hqmx — CVSS 7.8 High Stack buffer overflow in the tcpprep --services file parser
GHSA-m6w7-8497-g9c9 — CVSS 7.7 High Heap out-of-bounds read via --pktlen with --preload-pcap
GHSA-5q26-7fxx-v8fh — CVSS 7.1 High Heap out-of-bounds access in ARP address rewriting

(Everyone already on 4.5.5 has the fragroute and get_layer4_v6 advisories that were fixed alongside these — those were backported there separately, so they aren't new here.)

SECURITY.md is now at the repo root, picked up by GitHub's Security tab, and documents the disclosure policy and preferred reporting channel.

Build system

  • CMake (cmake -B build && cmake --build build) is now the primary, recommended way to build the suite, with feature-for-feature parity to the autotools ./configure flags.
  • GNU AutoGen is no longer required to build from a git checkout (only python3 and asciidoctor); it remains needed only for one legacy template file.
  • Release tarballs ship pre-built files for both build systems, so a tarball build needs neither python3 nor asciidoctor.

Credits

Thanks to @dsseng for --loss, @Steve-Tech for reporting and diagnosing the jumbo-frame truncation, and tinyb0y for the security research behind this release's advisories.

What's Changed

  • xdp: revert the top-speed default for --xdp-batch-size back to 1 (#1084) — now that sends pipeline across the whole umem, a batch of 1 already reaches line rate on a 1GigE e1000 (941 Mbps / 305k pps). --xdp-batch-size stays available for links this can't yet saturate — 100GigE and up, especially with small packets — where a deeper batch may still help
  • xdp: pipeline AF_XDP sends by spreading packets over the whole umem instead of recycling the first batch_size frames (#1084) — the send path no longer waits for each batch to complete before preparing the next packet, only when the next batch would reuse a frame still in flight. The umem is 4096 frames whether used or not, so this costs no extra memory; at a batch of 64 only 1.5% of it was being used. End-of-replay draining now covers AF_XDP too, so the reported counts describe what actually reached the wire
  • xdp: batch AF_XDP sends 64 deep by default when replaying at top speed (#1084) — the send path waits for each batch to complete before preparing the next packet, so a batch of one costs a full TX completion round-trip per packet: ~13k pps on an e1000 against ~254k at 64. Paced replays keep a batch of 1, since --pps/--mbps/--multiplier are only honoured there
  • xdp: fix --xdp-batch-size collapsing throughput (#1084) — a full batch of TX descriptors was reserved but only the filled ones submitted, so libxdp's cached producer index crept ahead on every short batch until the ring looked full; --xdp-batch-size=64 against a 179-packet pcap ran at 120 pps, now ~685k. Unused reservations are handed back
  • xdp: fix --xdp delivering only the first --loop iteration and then wedging (#1082) — the TX ring's cached producer/consumer indices were zeroed between loops, desynchronising them from the kernel's and stranding every later descriptor; libxdp maintains them itself
  • xdp: add --xdp-queue to select which adapter queue the AF_XDP socket binds to, instead of always using queue 0 (#1082)
  • xdp: fall back to the default injection method, with a warning, when AF_XDP cannot be set up on the adapter, rather than failing outright; --xdp-no-fallback restores the hard error for benchmarking, wh...
Read more

v4.5.5

Choose a tag to compare

@fklassen fklassen released this 24 Jul 00:53
v4.5.5

This update contains only security fixes and their test coverage.

All of these bugs are present in 4.5.4 and earlier. The get_layer4_v6 over-read is reached by reading an untrusted pcap with any of the tools. The remainder are reached through tcprewrite --fragroute=<rules-file> and require only an attacker-influenced fragroute rules file — no crafted packet content. Builds without libdnet (fragroute support disabled) are unaffected.

What's Changed

  • 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 " -> -> ..." 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]. 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.

Full Changelog: v4.5.4...v4.5.5

Download the release by clicking the tcpreplay* assets below ...

v4.5.4

Choose a tag to compare

@fklassen fklassen released this 23 Jul 02:12
v4.5.4

This update contains only security advisory updates.

What's Changed

  • 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) passed sizeof(pkt->pkt_data) - ETH_HDR_LEN as the buffer-capacity bound to inet_add_option(); pkt_data is a pointer, so sizeof() was 8 on 64-bit builds and the subtraction underflowed size_t to near SIZE_MAX, disabling the bounds check and letting libdnet's option-insertion memmove() write past the packet's heap allocation. The bound is now computed from the real buffer extent (pkt->pkt_buf + pkt->pkt_buf_size - pkt->pkt_ip). Reported by tinyb0y.
  • SECURITY: fix heap buffer overflow in the tcprewrite fragroute ip6_opt module (GHSA-2wmf-4p77-784q, CWE-787). ip6_opt_apply() (src/fragroute/mod_ip6_opt.c) inserted IPv6 routing/extension headers with memmove()/memcpy() without checking that the inserted bytes fit the packet's remaining buffer headroom. Both the route and raw paths now verify pkt_end + offset stays within the allocation and skip the packet otherwise. Reported by tinyb0y.
  • SECURITY: fix the same class of unchecked option-insertion overflow in the fragroute ip_opt module (src/fragroute/mod_ip_opt.c), which used a fixed PKT_BUF_LEN - ETH_HDR_LEN bound that overcounts capacity by the buffer's lead-alignment pad on small packets; it now uses the same real buffer-extent bound as tcp_opt.
  • SECURITY: fix SEGV in the tcpedit DLT_JUNIPER_ETHER plugin when used as a decoder (GHSA-ww62-mxv7-pg55, CWE-704, CWE-843). dlt_jnpr_ether_post_init()/_cleanup()/_decode()/_proto()/_get_mac()/_l2len() (src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.c) read ctx->encoder->config to get the plugin's own config, but this plugin only ever operates as a decoder (packet encoding is unsupported) - ctx->encoder pointed at an unrelated plugin's config struct, a type confusion that crashed tcpedit_dlt_getplugin() when processing DLT_JUNIPER_ETHER input, e.g. via tcprewrite --dlt=enet. Fixed by reading ctx->decoder->config in all six sites. Reported and originally patched by jiezhuzzz.
  • SECURITY: fix crash in remove_settings() on failed text_mmap (GHSA-5cjx-62pj-pmgq, CWE-476). remove_settings() (libopts/save.c), reachable from the AutoOpts option-file save/rewrite path (e.g. via --load-opts), dereferenced the pointer returned by text_mmap() without checking for MAP_FAILED, unlike the other two callers in configfile.c. A missing/inaccessible/wrong-type/empty settings file crashed the program. Fixed with the same TEXT_MMAP_FAILED_ADDR() guard already used elsewhere in the codebase. Reported by jiezhuzzz.
  • SECURITY: fix buffer overflow in the KHIAL sendpacket() path (GHSA-pjh6-6hrw-vcwr, CWE-787, CVSS 6.6). buffer_payload_size (src/common/sendpacket.c) was computed as sizeof(buffer) + sizeof(struct pcap_pkthdr) instead of sizeof(buffer) - sizeof(struct pcap_pkthdr), overstating the KHIAL send buffer's available space by 48 bytes (64-bit) and letting memcpy() overflow the static buffer for packets >= 10024 bytes sent via tcpreplay --intf1=; the following write() had the same problem in reverse, reading past the buffer into the character device. Fixed the calculation and added an explicit length check that rejects oversized packets before either memcpy or write() touch the buffer. Reported by 360AlphaLab.

Full Changelog: v4.5.3...v4.5.4

Download the release by clicking the tcpreplay* assets below ...

v4.5.3

Choose a tag to compare

@fklassen fklassen released this 19 Jul 18:24
v4.5.3

Announcing Tcpreplay v4.5.3 This update contains mostly bug fixes.

What's Changed

  • v4.5.3 by @fklassen in #980
  • Refs #984: sendpacket bounded EAGAIN/ENOBUFS retry (merges #986 + fixups) by @fklassen in #996
  • Bug #984 endless retries on enobufs eagain by @fklassen in #997
  • gitignore: share .claude/skills/, document code-review-graph MCP setup by @fklassen in #998
  • send_packets: fix miscalibrated overflow guards in calc_sleep_time (#974) by @fklassen in #999
  • migrate autoopts -> getopt + asciidoctor by @GabrielGanne in #991
  • Revert "migrate autoopts -> getopt + asciidoctor" by @fklassen in #1000
  • fix fragroute overflow on packets with too many MPLS labels by @GabrielGanne in #993
  • tcprewrite - fix adding vlan tag with missing options by @GabrielGanne in #994
  • tcpprep - fix buffer overflow on truncated packets by @GabrielGanne in #995
  • fragroute: fix TAILQ_FOREACH_REVERSE portability across queue.h variants by @fklassen in #1001
  • sendpacket: stop inhibiting libbpf's default XDP program load for AF_XDP TX by @fklassen in #1002
  • sendpacket: warn when sending on a down/no-carrier interface (Linux) by @fklassen in #1003
  • tcpreplay: fix --multiplier timing drift (takes over #915) by @fklassen in #1004
  • send_packets: bound and make abortable the netmap TX-ring drain wait by @fklassen in #1005
  • netmap: remove stray switch defaults in nm_do_ioctl() breaking --netmap by @fklassen in #1006
  • sendpacket: route "zc:" PF_RING ZC device names through libpcap by @fklassen in #1007
  • tcprewrite: rewrite addresses embedded in ICMPv6 error messages by @fklassen in #1008
  • docs: document autogen.sh requirement for git checkouts by @fklassen in #1009
  • tcpliveplay: call pcap_breakloop() from the SIGALRM handler by @fklassen in #1010
  • tcpedit: fix wrong end-of-buffer pointer in TCP-sequence/portmap rewrite by @fklassen in #1013
  • tcpr_random: fix signed left-shift undefined behavior (does not fix #1011 - see comments) by @fklassen in #1012
  • configure: stop --with-netmap from leaking -I/sys into CFLAGS by @fklassen in #1014
  • update Copyright to 2026 by @fklassen in #1017

Full Changelog: v4.5.2...v4.5.3

Download the release by clicking the tcpreplay* assets below ...

v4.5.2

Choose a tag to compare

@fklassen fklassen released this 27 Aug 02:54
v4.5.2
9816991

Announcing Tcpreplay v4.5.1. This update contains mostly bug fixes.

What's Changed

New Contributors

Full Changelog: v4.5.1...v4.5.2

Download the release by clicking the tcpreplay* assets below ...

v4.5.1

Choose a tag to compare

@fklassen fklassen released this 12 Jul 17:30
v4.5.1
0ba7d17

Announcing v4.5.1

This release contains contributions from a record number of new contributors. This is greatly appreciated since I am a team of one, and do Tcpreplay maintenance in my spare time.

There are many bug fixes and new features. Most notable features:

  • AF_XDP socket support - if you have a newer Linux kernel, you will be able to transmit at line rates without having to install 3rd party kernel modules (e.g. netmap, PF_RING)
  • -w tcpreplay option - this overrides the -i option, and allows you to write to a PCAP file rather than an interface
  • --include and --exclude tcpreplay options - allows replay of a list of specific packet numbers to replay. This may slow things down, so consider using in combination with -w.
  • --fixhdrlen tcpreplay option - added to control action on packet length changes
  • -W tcpreplay option - suppress warnings when replaying
  • SLL2( Linux "cooked" capture encapsulation v2)
  • Haiku support

What's Changed

New Contributors

Full Changelog: v4.4.4...v4.5.1

v4.4.4

Choose a tag to compare

@fklassen fklassen released this 11 Jun 18:18
v4.4.4
2bf3b37

This is Tcpreplay suite 4.4.4 This release contains bug fixes only.

What's Changed

New Contributors

Full Changelog: v4.4.3...v4.4.4

Download the release by clicking the tcpreplay* assets below ...

v4.4.3

Choose a tag to compare

@fklassen fklassen released this 02 Jan 08:03
v4.4.3
bcb107a

This is Tcpreplay suite 4.4.3 This release contains bug fixes only.

What's Changed

Full Changelog: v4.4.2...v4.4.3

Download the release by clicking the tcpreplay* assets below ...

v4.4.2

Choose a tag to compare

@fklassen fklassen released this 26 Aug 22:15
v4.4.2
1c0e25e

This is Tcpreplay suite 4.4.2

This release contains bug fixes only.

What's Changed

New Contributors

Full Changelog: v4.4.1...v4.4.2