]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
7 days agoCI: Consistently add a top-level `permissions` definition to GHA workflows
Tim Duesterhus [Sun, 12 Apr 2026 19:24:19 +0000 (21:24 +0200)] 
CI: Consistently add a top-level `permissions` definition to GHA workflows

This makes it easy to verify the permissions and to apply them to all jobs
within a given workflow.

7 days agoCI: Drop obsolete `packages: write` permission from `quic-interop-*.yml`
Tim Duesterhus [Sun, 12 Apr 2026 19:24:18 +0000 (21:24 +0200)] 
CI: Drop obsolete `packages: write` permission from `quic-interop-*.yml`

This is no longer necessary since dfe1de4335f12d8ce436b906b2b6cddfcb8274c9.

7 days agoMINOR: ot: renamed the variable dbg_indent_level to flt_ot_dbg_indent_level
Miroslav Zagorac [Fri, 20 Jan 2023 23:44:13 +0000 (00:44 +0100)] 
MINOR: ot: renamed the variable dbg_indent_level to flt_ot_dbg_indent_level

The thread-local variable dbg_indent_level used a generic name that could
collide with identifiers in other compilation units.  Renamed it to
flt_ot_dbg_indent_level so that it carried the flt_ot_ prefix consistent
with the rest of the OpenTracing filter namespace.  The rename covered the
declaration, definition, and all macro references in debug.h, parser.c and
util.c.

7 days agoBUILD: ot: removed explicit include path when building opentracing filter
Miroslav Zagorac [Thu, 19 Jan 2023 08:50:56 +0000 (09:50 +0100)] 
BUILD: ot: removed explicit include path when building opentracing filter

The -Iaddons/ot/include flag in OT_CFLAGS allowed source files to use a
bare #include "include.h", which was fragile because it depended on the
compiler search path.  Removed that flag from the Makefile and changed
every source file under addons/ot/src/ to use the relative include path
../include/include.h instead.  This made header resolution explicit and
consistent with standard addon conventions.

7 days agoBUG/MINOR: ot: fixed wrong NULL check in flt_ot_parse_cfg_group()
Miroslav Zagorac [Wed, 18 Jan 2023 18:33:21 +0000 (19:33 +0100)] 
BUG/MINOR: ot: fixed wrong NULL check in flt_ot_parse_cfg_group()

After calling flt_ot_conf_group_init() and storing the result in
flt_ot_current_group, the code incorrectly checked flt_ot_current_config
for NULL instead of the newly assigned flt_ot_current_group.  This meant
a failed group init was never detected and the error path was never taken.

7 days agoBUG/MINOR: ot: removed dead code in flt_ot_parse_cfg_str()
Miroslav Zagorac [Wed, 18 Jan 2023 16:14:16 +0000 (17:14 +0100)] 
BUG/MINOR: ot: removed dead code in flt_ot_parse_cfg_str()

The local variable str was declared but never assigned a value other than
NULL.  The error-handling block that called flt_ot_conf_str_free(&str) on
it was therefore a no-op.  Removed both the unused variable and the dead
cleanup path.

7 days agoCLEANUP: ot: use the item API for the variables trees
Miroslav Zagorac [Thu, 25 Sep 2025 22:13:12 +0000 (00:13 +0200)] 
CLEANUP: ot: use the item API for the variables trees

In flt_ot_vars_scope_dump(), switched from cebu64_first()/cebu64_next() to
cebu64_imm_first()/cebu64_imm_next() for iterating the variable name trees.
Since this function only reads variables under a read lock, the immutable
traversal API is the correct choice.  Also updated the container_of()
member from 'node' to 'name_node' to match the current struct var layout.

7 days agoDOC: otel: added README.md overview document
Miroslav Zagorac [Wed, 8 Apr 2026 21:28:00 +0000 (23:28 +0200)] 
DOC: otel: added README.md overview document

Added a Markdown-formatted overview covering features, build instructions,
configuration, scope keywords, CLI commands, performance benchmarks and
test configurations.

7 days agoMINOR: otel: changed instrument attr to use sample expressions
Miroslav Zagorac [Mon, 6 Apr 2026 04:33:40 +0000 (06:33 +0200)] 
MINOR: otel: changed instrument attr to use sample expressions

Replaced the static key-value attribute storage in update-form instruments
with sample-evaluated attributes, matching the log-record attr change.
The 'attr' keyword now accepts a key and a HAProxy sample expression
evaluated at runtime.

The struct (conf.h) changed from otelc_kv/attr_len to a list of
flt_otel_conf_sample entries.  The parser (parser.c) calls
flt_otel_parse_cfg_sample() with n=1 per attr keyword.  At runtime
(event.c) each attribute is evaluated via flt_otel_sample_eval() and
added via flt_otel_sample_add_kv() to a bare flt_otel_scope_data_kv,
which is passed to the meter.

Updated documentation, debug macro and test configurations.

7 days agoMINOR: otel: changed log-record attr to use sample expressions
Miroslav Zagorac [Fri, 3 Apr 2026 10:33:26 +0000 (12:33 +0200)] 
MINOR: otel: changed log-record attr to use sample expressions

Replaced the static key-value attribute storage in log-record with
sample-evaluated attributes.  The 'attr' keyword now accepts a key and a
HAProxy sample expression evaluated at runtime, instead of a static string
value.

The struct (conf.h) changed from otelc_kv/attr_len to a list of
flt_otel_conf_sample entries.  The parser (parser.c) calls
flt_otel_parse_cfg_sample() with n=1 per attr keyword.  At runtime
(event.c) each attribute is evaluated via flt_otel_sample_eval() and added
via flt_otel_sample_add_kv() to a bare flt_otel_scope_data_kv, which is
passed to logger->log_span().

Updated documentation, debug macro and test configurations.

7 days agoMINOR: otel: added flt_otel_sample_eval and exposed flt_otel_sample_add_kv
Miroslav Zagorac [Thu, 2 Apr 2026 14:03:12 +0000 (16:03 +0200)] 
MINOR: otel: added flt_otel_sample_eval and exposed flt_otel_sample_add_kv

Factored the sample evaluation logic out of flt_otel_sample_add() into a
new flt_otel_sample_eval() function that evaluates a sample definition
into an otelc_value.  Both the log-format path and the bare sample
expression path are handled, with a flag_native parameter controlling
native type preservation for single-expression samples.
flt_otel_sample_add() now calls flt_otel_sample_eval() and dispatches the
result.

Made flt_otel_sample_add_kv() non-static so callers outside util.c can
add key-value pairs directly to a bare flt_otel_scope_data_kv without
requiring the full flt_otel_scope_data structure.

7 days agoDOC: otel: added cross-cutting design patterns document
Miroslav Zagorac [Wed, 1 Apr 2026 02:35:51 +0000 (04:35 +0200)] 
DOC: otel: added cross-cutting design patterns document

Added README-design covering the internal design patterns that span
multiple source files: X-macro code generation, type-safe generic macros,
error handling architecture, thread safety model, sample evaluation
pipeline, rate limiting, memory management, context propagation, debug
infrastructure, idle timeout mechanism, group action integration and CLI
runtime control.

7 days agoDOC: otel: test: added speed test guide and benchmark results
Miroslav Zagorac [Wed, 25 Mar 2026 11:17:03 +0000 (12:17 +0100)] 
DOC: otel: test: added speed test guide and benchmark results

The test directory gained a speed test guide (README-test-speed)
explaining how to run performance benchmarks at various rate-limit levels,
together with benchmark result files for the standalone, composite,
context-propagation, and frontend-backend test configurations.

7 days agoDOC: otel: test: added test README-* files
Miroslav Zagorac [Sat, 21 Mar 2026 17:39:52 +0000 (18:39 +0100)] 
DOC: otel: test: added test README-* files

Added README documentation for each test configuration (sa, cmp, ctx,
fe-be, empty, full) describing event coverage, signal usage, instrument
tables, span hierarchies and run instructions.

7 days agoDOC: otel: added documentation
Miroslav Zagorac [Sun, 12 Apr 2026 10:07:17 +0000 (12:07 +0200)] 
DOC: otel: added documentation

Added the full documentation set for the OpenTelemetry filter.

The main README served as the user-facing guide covering build
instructions, core OpenTelemetry concepts, the complete filter
configuration reference, usage examples with worked scenarios,
CLI commands, and known limitations.

Supplementary documents provided a detailed configuration guide with
worked examples (README-configuration), an internal C structure reference
for developers (README-conf), a function reference organized by source
file (README-func), an architecture and implementation review
(README-implementation), and miscellaneous notes (README-misc).

7 days agoMINOR: otel: test: added full-event test config
Miroslav Zagorac [Fri, 13 Mar 2026 21:12:49 +0000 (22:12 +0100)] 
MINOR: otel: test: added full-event test config

Added the 'full' test configuration that exercises all 29 supported OTel
filter events with all three signal types (traces, metrics, logs).  Every
instrument definition has a corresponding update.

7 days agoMINOR: otel: added log-record signal support
Miroslav Zagorac [Sat, 7 Mar 2026 14:28:10 +0000 (15:28 +0100)] 
MINOR: otel: added log-record signal support

Added "log-record" as the third OpenTelemetry signal alongside traces
(span) and metrics (instrument).  This includes the
flt_otel_conf_log_record structure definition, parser keyword defines,
the otel-scope section parser with optional "id", "event", "span", and
"attr" keywords followed by sample fetch expressions or a log-format
string, init/free lifecycle, scope list wiring, log-format evaluation
in flt_otel_scope_run_instrument_record(), a test configuration example,
log-record span reference validation in flt_otel_check(), and logger
handle creation, startup, and teardown in the filter lifecycle.

7 days agoMINOR: otel: added metrics instrument support
Miroslav Zagorac [Mon, 2 Mar 2026 08:41:57 +0000 (09:41 +0100)] 
MINOR: otel: added metrics instrument support

Added the "instrument" keyword to otel-scope sections for recording metric
measurements alongside traces.

Introduced flt_otel_conf_instrument holding instrument type, description,
unit, sample expressions, and optional key-value attributes.  The
supported synchronous integer-precision instrument types were counters,
histograms, up-down counters, and gauges.

Instruments followed a two-form design: a "create" form defined a new
instrument with its type and value expression, while an "update" form
recorded measurements against an existing instrument with per-scope
attributes.

Instrument creation was performed lazily at first use with HA_ATOMIC_CAS
to guarantee thread-safe one-time initialization.  The configuration
check phase validated that every update-form had a matching create-form
definition and that create-form names were unique across all scopes.

The meter lifecycle was integrated into filter init and deinit, starting
the meter alongside the tracer and shutting it down during cleanup.

7 days agoMINOR: otel: added span link support
Miroslav Zagorac [Thu, 26 Feb 2026 10:09:33 +0000 (11:09 +0100)] 
MINOR: otel: added span link support

Added span link support, allowing a span to reference other spans or
extracted contexts without establishing a parent relationship.

Introduced the flt_otel_conf_link structure and added a links list to
flt_otel_conf_span.  The parser accepted both an inline syntax on the span
declaration line ("span <name> link <target>") and a standalone multi-
argument form ("link <span> ..."), each creating a conf_link entry
appended to the span's link list.

At runtime, each configured link name was resolved against the active
spans and extracted contexts in the runtime context.  Resolved references
were collected into flt_otel_scope_data_link entries and passed to the C
wrapper add_link API during span creation.

Initialization, cleanup, and debug dump routines were added for the link
data structures at both configuration and runtime levels.

7 days agoMINOR: otel: test: added test and benchmark suite for the OTel filter
Miroslav Zagorac [Tue, 27 Jan 2026 12:02:59 +0000 (13:02 +0100)] 
MINOR: otel: test: added test and benchmark suite for the OTel filter

Added a test suite under addons/otel/test/ for the OpenTelemetry filter.
Five scenarios exercise different filter capabilities: standalone (sa)
covers all hook points including idle-timeout heartbeats, metrics and log
records; compact (cmp) covers the full request/response lifecycle with
ACL-based error handling; context (ctx) tests explicit inject/extract
propagation through numbered context variables; frontend/backend (fe/be)
tests distributed tracing across two HAProxy instances; and empty tests
bare filter initialisation with no active scopes.

A performance benchmarking script (test-speed.sh) uses wrk to measure
throughput and latency at different rate-limit settings (100% through 0%,
disabled, and filter-off).  Each scenario includes comprehensive YAML
exporter definitions covering OTLP file/gRPC/HTTP, ostream, memory,
Zipkin, and Elasticsearch backends.

7 days agoMINOR: otel: added log-format support to the sample parser and runtime
Miroslav Zagorac [Tue, 3 Feb 2026 20:36:11 +0000 (21:36 +0100)] 
MINOR: otel: added log-format support to the sample parser and runtime

Extended flt_otel_parse_cfg_sample() to accept log-format strings in
addition to bare sample expressions.  Added lf_expr and lf_used fields
to flt_otel_conf_sample.

Extended flt_otel_sample_add() to evaluate log-format expressions when
lf_used was set.

7 days agoMEDIUM: otel: added group action for rule-based scope execution
Miroslav Zagorac [Sun, 12 Apr 2026 10:20:15 +0000 (12:20 +0200)] 
MEDIUM: otel: added group action for rule-based scope execution

Added the "otel-group" action keyword that allows executing a named group
of OTel scopes from HAProxy TCP and HTTP action rule contexts.

The new group.c module registers the "otel-group" keyword for all four
action contexts (tcp-request, tcp-response, http-request, http-response)
and implements the action lifecycle callbacks.

The parser flt_otel_group_parse() accepts a filter ID and group ID as
arguments, duplicates them into the action rule's argument slots, and
wires up the check, action, and release callbacks.

The post-parse validator flt_otel_group_check() resolves the filter ID and
group ID string references into direct configuration pointers by searching
the proxy's filter list for a matching OTel filter and then looking up the
named group within that filter's configuration.

The action handler flt_otel_group_action() retrieves the filter and group
configuration from the resolved rule arguments, verifies the filter is
attached to the stream and not disabled, then iterates through all scopes
in the group and executes each via flt_otel_scope_run() with a shared
timestamp pair.  This allows operators to trigger OTel instrumentation
conditionally from HAProxy rules, for example applying different tracing
scopes based on ACL conditions or request properties.

7 days agoMEDIUM: otel: added CLI commands for runtime filter management
Miroslav Zagorac [Sun, 12 Apr 2026 09:31:30 +0000 (11:31 +0200)] 
MEDIUM: otel: added CLI commands for runtime filter management

Added HAProxy CLI commands that allow runtime inspection and modification
of OTel filter settings without requiring a configuration reload.

The new cli.c module registers CLI keywords under the "otel" prefix and
implements the following commands: flt_otel_cli_parse_status() displays a
comprehensive status report of all OTel filter instances including filter
ID, proxy, disabled state, hard-error mode, logging state, rate limit,
analyzer bits, and SDK diagnostic message count;
flt_otel_cli_parse_disabled() enables or disables filtering across all
instances; flt_otel_cli_parse_option() toggles the hard-error mode that
controls whether errors disable the filter for a stream or are silently
ignored; flt_otel_cli_parse_logging() manages the logging state with
support for off, on, and dontlog-normal modes; flt_otel_cli_parse_rate()
adjusts the sampling rate limit as a floating-point percentage; and
flt_otel_cli_parse_debug() sets the debug verbosity level in debug builds.
All modifications are applied atomically across every OTel filter instance
in every proxy.

The CLI initialization is called from flt_otel_ops_init() during filter
startup via flt_otel_cli_init(), which registers the keyword table through
cli_register_kw().

Supporting changes include the FLT_OTEL_U32_FLOAT macro for converting the
internal uint32_t rate representation to a human-readable percentage, the
FLT_OTEL_PROXIES_LIST_START/END iteration macros for traversing all OTel
filter instances across the proxy list, and flt_otel_filters_dump() for
debug logging of filter instances.

7 days agoMINOR: otel: added prefix-based variable scanning
Miroslav Zagorac [Wed, 11 Feb 2026 05:55:44 +0000 (06:55 +0100)] 
MINOR: otel: added prefix-based variable scanning

Introduced an alternative variable scanning strategy that directly walked
the CEB tree of HAProxy's variable store instead of maintaining a separate
tracking buffer.

The Makefile auto-detected whether struct var carried a "name" member
by inspecting include/haproxy/vars-t.h and conditionally defined
USE_OTEL_VARS_NAME.  When enabled, the tracking buffer (flt_otel_ctx) and
its callback type were compiled out and replaced by direct tree walks.

flt_otel_vars_unset() walked the CEB tree for the resolved scope, removed
every variable whose normalized name matched the given prefix followed by
a dot, and adjusted the variable accounting.  flt_otel_vars_get()
performed the same prefix scan under a read lock, denormalized each
matching variable name back to its original OTel form, and assembled the
results into an otelc_text_map.

A helper flt_otel_vars_get_scope() was added to resolve scope name strings
("txn", "sess", "proc", "req", "res") to the corresponding HAProxy
variable store.  The set path skipped the tracking buffer update when
prefix scanning was available.

7 days agoMEDIUM: otel: added HAProxy variable storage for context propagation
Miroslav Zagorac [Sun, 12 Apr 2026 09:25:14 +0000 (11:25 +0200)] 
MEDIUM: otel: added HAProxy variable storage for context propagation

Added support for storing OTel span context in HAProxy transaction
variables as an alternative to HTTP headers, enabled by the OTEL_USE_VARS
compile flag.

The new vars.c module implements variable-based context propagation
through the HAProxy variable subsystem.  Variable names are constructed
from a configurable prefix and the OTel propagation key, with dots
normalized to underscores for HAProxy variable name compatibility
and denormalized back during retrieval.  The module provides
flt_otel_var_register() to pre-register variables at parse time,
flt_otel_var_set() and flt_otel_vars_unset() to store and clear context
key-value pairs in the txn scope, flt_otel_vars_get() to collect all
variables matching a prefix into an otelc_text_map for context extraction,
and flt_otel_vars_dump() for debug logging of all OTel variables.

The inject/extract keywords in the scope parser now accept an optional
"use-vars" argument alongside "use-headers", controlled by the new
FLT_OTEL_CTX_USE_VARS flag.  Both storage types can be used simultaneously
on the same span context, allowing context to be propagated through both
HTTP headers and variables.

The scope runner in event.c was extended to handle variable-based
context in parallel with headers: during extraction, it reads matching
variables via flt_otel_vars_get() when FLT_OTEL_CTX_USE_VARS is set;
during injection, it stores each propagation key as a variable via
flt_otel_var_set().  The unused resource cleanup now also unsets context
variables when removing failed extraction contexts.

The filter attach callback registers and sets the sess.otel.uuid variable
with the generated session UUID, making the trace identifier available to
HAProxy log formats and ACL expressions.

The feature is conditionally compiled: the OTEL_USE_VARS flag controls
whether vars.c is included in the build and whether the "use-vars" keyword
is available in the configuration parser.

7 days agoMEDIUM: otel: added HTTP header operations for context propagation
Miroslav Zagorac [Sun, 12 Apr 2026 09:20:59 +0000 (11:20 +0200)] 
MEDIUM: otel: added HTTP header operations for context propagation

Added the HTTP header manipulation layer that enables span context
injection into and extraction from HAProxy's HTX message buffers,
completing the end-to-end context propagation path.

The new http.c module implements three public functions:
flt_otel_http_headers_get() extracts HTTP headers matching a name prefix
from the channel's HTX buffer into an otelc_text_map structure, stripping
the prefix and separator dash from header names before storage;
flt_otel_http_header_set() constructs a full header name from a prefix and
suffix joined by a dash, removes all existing occurrences, and optionally
adds the header with a new value; and flt_otel_http_headers_remove()
removes all headers matching a given prefix.  A debug-only
flt_otel_http_headers_dump() logs all HTTP headers from a channel at
NOTICE level.

The scope runner in event.c now extracts propagation contexts from HTTP
headers before processing spans: for each configured extract context, it
calls flt_otel_http_headers_get() to read matching headers into a text
map, then passes the text map to flt_otel_scope_context_init() which
extracts the OTel span context from the carrier.  After span execution,
the span runner injects the span context back into HTTP headers via
flt_otel_inject_http_headers() followed by flt_otel_http_header_set()
for each propagation key.

The unused resource cleanup in flt_otel_scope_free_unused() now also
removes contexts that failed extraction by deleting their associated
HTTP headers via flt_otel_http_headers_remove() before freeing the scope
context structure.

7 days agoMEDIUM: otel: added context propagation via carrier interfaces
Miroslav Zagorac [Sun, 12 Apr 2026 09:17:11 +0000 (11:17 +0200)] 
MEDIUM: otel: added context propagation via carrier interfaces

Added the span context injection and extraction layer that bridges the
OTel C wrapper's propagation API with HAProxy's HTTP headers and text map
carriers.

The new otelc.c module implements four public functions that wrap the
OTel C wrapper's context propagation methods: flt_otel_inject_text_map()
and flt_otel_inject_http_headers() serialize a span's context into
a text map or HTTP headers carrier for outbound propagation, while
flt_otel_extract_text_map() and flt_otel_extract_http_headers()
deserialize an inbound carrier into an otelc_span_context for parent
linking.

Each direction uses a pair of callbacks registered on the carrier
structure.  The injection writers (flt_otel_text_map_writer_set_cb and
flt_otel_http_headers_writer_set_cb) store key-value pairs emitted by the
SDK into the carrier's text map via OTELC_TEXT_MAP_ADD().  The extraction
readers (flt_otel_text_map_reader_foreach_key_cb and
flt_otel_http_headers_reader_foreach_key_cb) iterate the carrier's text
map entries and pass each pair to the SDK's handler callback.

The scope context initialization in flt_otel_scope_context_init() now
calls flt_otel_extract_http_headers() to extract the span context from the
provided text map carrier and stores it in the scope context structure,
making extracted contexts available for parent linking in subsequent span
creation.

7 days agoMEDIUM: otel: implemented scope execution and span management
Miroslav Zagorac [Sun, 12 Apr 2026 08:58:38 +0000 (10:58 +0200)] 
MEDIUM: otel: implemented scope execution and span management

Implemented the scope execution engine that creates OTel spans, evaluates
sample expressions to collect telemetry data, and manages span lifecycle
during request and response processing.

The scope runner flt_otel_scope_run() was expanded from a stub into a
complete implementation that evaluates ACL conditions on the scope,
extracts span contexts from HTTP headers when configured, iterates over
the scope's span definitions calling flt_otel_scope_run_span() for each,
marks and finishes completed spans, and cleans up unused runtime
resources.

The span runner flt_otel_scope_run_span() creates OTel spans via the
tracer with optional parent references (from other spans or extracted
contexts), collects telemetry by calling flt_otel_sample_add() for each
configured attribute, event, baggage and status entry, then applies the
collected data to the span (attributes, events with their own key-value
arrays, baggage items, and status code with description) and injects the
span context into HTTP headers when configured.

The sample evaluation layer converts HAProxy sample expressions into OTel
telemetry data.  flt_otel_sample_add() evaluates each sample expression
against the stream, converts the result via flt_otel_sample_to_value()
which preserves native types (booleans as OTELC_VALUE_BOOL, integers as
OTELC_VALUE_INT64, all others as strings), and routes the key-value pair
to the appropriate collector based on the sample type (attribute, event,
baggage, or status).  The key-value arrays grow dynamically using the
FLT_OTEL_ATTR_INIT_SIZE and FLT_OTEL_ATTR_INC_SIZE constants.

Span finishing is handled in two phases: flt_otel_scope_finish_mark()
marks spans and contexts for completion using exact name matching or
wildcards ("*" for all, "*req*" for request-direction, "*res*" for
response-direction), and flt_otel_scope_finish_marked() ends all marked
spans with a common monotonic timestamp and destroys their contexts.

7 days agoMEDIUM: otel: wired OTel C wrapper library integration
Miroslav Zagorac [Sun, 12 Apr 2026 08:52:53 +0000 (10:52 +0200)] 
MEDIUM: otel: wired OTel C wrapper library integration

Connected the OpenTelemetry C wrapper library to the filter lifecycle by
implementing the library initialization, tracer creation, memory and
thread callbacks, shutdown sequence, and span completion.

The flt_otel_lib_init() function now verifies the C wrapper library
version against the compiled headers, calls otelc_init() with the absolute
configuration file path, and creates the tracer via otelc_tracer_create().
On success, it registers HAProxy pool-based memory callbacks
(flt_otel_mem_malloc, flt_otel_mem_free) and a thread ID callback
(flt_otel_thread_id) through otelc_ext_init(), so the C++ SDK allocates
span and context objects from pool_head_otel_span_context.  A custom log
handler (flt_otel_log_handler_cb) is registered via otelc_log_set_handler()
to count OTel SDK internal diagnostic messages in the flt_otel_drop_cnt
counter.

The per-thread init callback now starts the tracer thread via
OTELC_OPS(tracer, start) instead of unconditionally returning success.

The deinit callback saves the tracer handle before freeing the
configuration, then shuts down the library via otelc_deinit() after the
pool is destroyed, ensuring the ext callbacks remain valid while the
configuration structures are still being freed.  In debug builds, it logs
wrapper statistics, attach counters, and per-event HTX usage counters
before shutdown.

The runtime context cleanup in flt_otel_runtime_context_free() now ends
all active spans with a common monotonic timestamp via
OTELC_OPSR(span, end_with_options) before freeing them.  The scope context
cleanup in flt_otel_scope_context_free() now destroys the underlying OTel
span context via OTELC_OPSR(context, destroy).

The parser gained static storage for the debug memory tracker
(OTELC_DBG_MEM) and its initialization in the parse entry point, used when
compiled with the OTELC_DBG_MEM flag.

7 days agoMEDIUM: otel: implemented filter callbacks and event dispatcher
Miroslav Zagorac [Sun, 12 Apr 2026 08:30:03 +0000 (10:30 +0200)] 
MEDIUM: otel: implemented filter callbacks and event dispatcher

Replaced the stub filter callbacks with full implementations that dispatch
OTel events through the scope execution engine, and added the supporting
debug, error handling and utility infrastructure.

The filter lifecycle callbacks (init, deinit, init_per_thread) now
initialize the OpenTelemetry C wrapper library, create the tracer from the
instrumentation configuration file, enable HTX stream filtering, and clean
up the configuration and memory pools on shutdown.

The stream callbacks (attach, stream_start, stream_set_backend,
stream_stop, detach, check_timeouts) create the per-stream runtime context
on attach with rate-limit based sampling, fire the corresponding OTel
events (on-stream-start, on-backend-set, on-stream-stop), manage the
idle timeout timer with reschedule logic in detach, and free the runtime
context in check_timeouts.  The attach callback also registers the
required pre and post channel analyzers from the instrumentation
configuration.

The channel callbacks (start_analyze, pre_analyze, post_analyze,
end_analyze) register per-channel analyzers, map analyzer bits to event
indices via flt_otel_get_event(), and dispatch the matching events.
The end_analyze callback also fires the on-server-unavailable event
when response analyzers were configured but never executed.

The HTTP callbacks (http_headers, http_end, http_reply, and the debug-only
http_payload and http_reset) dispatch their respective request/response
events based on the channel direction.

The event dispatcher flt_otel_event_run() in event.c iterates over all
scopes matching a given event index and calls flt_otel_scope_run() for
each, sharing a common monotonic and wall-clock timestamp across all spans
within a single event.

Error handling is centralized in flt_otel_return_int() and
flt_otel_return_void(), which implement the hard-error/soft-error policy:
hard errors disable the filter for the stream, soft errors are silently
cleared.

The new debug.h header provides conditional debug macros
(FLT_OTEL_DBG_ARGS, FLT_OTEL_DBG_BUF) and the FLT_OTEL_LOG macro for
structured logging through the instrumentation's log server list.  The
utility layer gained debug-only label functions for channel direction,
proxy mode, stream position, filter type, and analyzer bit name lookups.

7 days agoMEDIUM: otel: added memory pool and runtime scope layer
Miroslav Zagorac [Sun, 12 Apr 2026 07:47:18 +0000 (09:47 +0200)] 
MEDIUM: otel: added memory pool and runtime scope layer

Added the memory pool management and the runtime scope layer that track
per-stream OTel spans and contexts during request processing.

The pool layer in pool.c manages HAProxy memory pools for the runtime
structures used by the filter: scope spans, scope contexts, runtime
contexts, and span contexts.  Each pool is conditionally compiled via
USE_POOL_OTEL_* macros defined in config.h and registered with
REGISTER_POOL().  The allocation functions (flt_otel_pool_alloc,
flt_otel_pool_strndup, flt_otel_pool_free) transparently fall back to
heap allocation when the corresponding pool is not enabled.  Trash buffer
helpers (flt_otel_trash_alloc, flt_otel_trash_free) provide scratch space
using either HAProxy's trash chunk pool or direct heap allocation.

The scope layer in scope.c implements the per-stream runtime state.  The
flt_otel_runtime_context structure is allocated when a stream starts and
holds the stream and filter references, hard-error/disabled/logging flags
copied from the instrumentation configuration, idle timeout state, a
generated UUID, and lists of active scope spans and extracted scope
contexts.  Scope spans (flt_otel_scope_span) carry the operation name,
fetch direction, the OTel span handle, and optional parent references
resolved from other spans or extracted contexts.  Scope contexts
(flt_otel_scope_context) hold an extracted span context obtained from
a carrier text map via the tracer.  The scope data structures
(flt_otel_scope_data) aggregate growable key-value arrays for attributes
and baggage, a linked list of named events with their own attribute
arrays, and a span status code with description, representing the
telemetry collected during a single event execution.

7 days agoMEDIUM: otel: added post-parse configuration check
Miroslav Zagorac [Sun, 12 Apr 2026 07:58:34 +0000 (09:58 +0200)] 
MEDIUM: otel: added post-parse configuration check

Implemented the flt_otel_ops_check() callback that validates the parsed
OTel filter configuration after all HAProxy configuration sections have
been processed.

The check callback performs the following validations: resolves deferred
sample fetch arguments under full frontend and backend capabilities,
verifies uniqueness of filter IDs across all proxies, ensures the
instrumentation section and its configuration file are present, checks
for duplicate group and scope section names, verifies that groups are not
empty, resolves group-to-scope and instrumentation-to-group/scope
cross-references by linking placeholder entries to their definitions,
detects unused scopes, counts root spans and warns when the count differs
from one, and accumulates the required channel analyzer bits from all used
scopes into the instrumentation configuration.

The commit also added the flt_otel_counters structure to track per-event
diagnostic counters in debug builds, the FLT_OTEL_ALERT macro for
filter-scoped error messages, and the FLT_OTEL_DBG_LIST macro for
iterating and dumping named configuration lists.

7 days agoMEDIUM: otel: added configuration parser and event model
Miroslav Zagorac [Sun, 12 Apr 2026 06:41:03 +0000 (08:41 +0200)] 
MEDIUM: otel: added configuration parser and event model

Added the full configuration parser that reads the OTel filter's external
configuration file and the event model that maps filter events to HAProxy
channel analyzers.

The event model in event.h defines an X-macro table
(FLT_OTEL_EVENT_DEFINES) that maps each filter event to its HAProxy
channel analyzer bit, sample fetch direction, and event name.  Events
cover stream lifecycle (start, stop, backend-set, idle-timeout), client
and server sessions, request analyzers (frontend and backend TCP and
HTTP inspection, switching rules, sticking rules, RDP cookie), response
analyzers (TCP inspection, HTTP response processing), and HTTP headers,
end, and reply callbacks.  The event names are partially compatible with
the SPOE filter.  The flt_otel_event_data[] table in event.c is generated
from the same X-macro and provides per-event metadata at runtime.

The parser in parser.c implements section parsers for the three OTel
configuration blocks: otel-instrumentation (tracer identity, log server,
config file path, groups, scopes, ACLs, rate-limit, options for
disabled/hard-errors/nolognorm, and debug-level), otel-group (group
identity and scope list), and otel-scope (scope identity, span definitions
with optional root/parent modifiers, attributes, events, baggages, status
codes, inject/extract context operations, finish lists, idle-timeout,
ACLs, and otel-event binding with optional if/unless ACL conditions).
Each section has a post-parse callback that validates the parsed state.

The top-level flt_otel_parse_cfg() temporarily registers these section
parsers, loads the external configuration file via parse_cfg(), and
handles deferred resolution of sample fetch arguments by saving them in
conf->smp_args for later resolution in flt_otel_check() when full frontend
and backend capabilities are available.  The main flt_otel_parse() entry
point was extended to parse the filter ID and config file keywords, verify
that insecure-fork-wanted is enabled, and wire the parsed configuration
into the flt_conf structure.

The utility layer gained flt_otel_strtod() and flt_otel_strtoll() for
validated string-to-number conversion used by rate-limit and debug-level
parsing.

7 days agoMEDIUM: otel: added configuration and utility layer
Miroslav Zagorac [Sun, 12 Apr 2026 05:30:57 +0000 (07:30 +0200)] 
MEDIUM: otel: added configuration and utility layer

Added the configuration structures that model the OTel filter's
instrumentation hierarchy and the utility functions that support the
configuration parser.

The configuration is organized as a tree rooted at flt_otel_conf, which
holds the proxy reference, filter identity, and lists of groups and
scopes.  Below it, flt_otel_conf_instr carries the instrumentation
settings: tracer handle, rate limiting, hard-error mode, logging state,
channel analyzers, and placeholder references to groups and scopes.
Groups (flt_otel_conf_group) aggregate scopes by name.  Scopes
(flt_otel_conf_scope) bind an event to its ACL condition, span context
declarations, span definitions and a list of spans scheduled for
finishing.  Spans (flt_otel_conf_span) carry attributes, events,
baggages and status entries, each represented as flt_otel_conf_sample
structures that pair a key with concatenated sample-expression arguments.

All configuration types share a common header macro (FLT_OTEL_CONF_HDR)
that embeds an identifier string, its length, a configuration line number,
and a list link.  Their init and free functions are generated by the
FLT_OTEL_CONF_FUNC_INIT and FLT_OTEL_CONF_FUNC_FREE macros in
conf_funcs.h, with per-type custom initialization and cleanup bodies.

The utility layer in util.c provides argument counting and concatenation
for the configuration parser, sample data to string conversion covering
boolean, integer, IPv4, IPv6, string and HTTP method types, and debug
helpers for dumping argument arrays and linked list state.

7 days agoMEDIUM: otel: added OpenTelemetry filter skeleton
Miroslav Zagorac [Mon, 13 Apr 2026 05:48:51 +0000 (07:48 +0200)] 
MEDIUM: otel: added OpenTelemetry filter skeleton

The OpenTelemetry (OTel) filter enables distributed tracing of requests
across service boundaries, export of metrics such as request rates,
latencies and error counts, and structured logging tied to trace context,
giving operators a unified view of HAProxy traffic through any
OpenTelemetry-compatible backend.

The OTel filter is implemented using the standard HAProxy stream filter
API.  Stream filters attach to proxies and intercept traffic at each stage
of processing: they receive callbacks on stream creation and destruction,
channel analyzer events, HTTP header and payload processing, and TCP data
forwarding.  This allows the filter to collect telemetry data at every
stage of the request/response lifecycle without modifying the core proxy
logic.

This commit added the minimum set of files required for the filter to
compile: the addon Makefile with pkg-config-based detection of the
opentelemetry-c-wrapper library, header files with configuration
constants, utility macros and type definitions, and the source files
containing stub filter operation callbacks registered through
flt_otel_ops and the "opentelemetry" keyword parser entry point.

The filter uses the opentelemetry-c-wrapper library from HAProxy
Technologies, which provides a C interface to the OpenTelemetry C++ SDK.
This wrapper allows HAProxy, a C codebase, to leverage the full
OpenTelemetry observability pipeline without direct C++ dependencies
in the HAProxy source tree.

  https://github.com/haproxytech/opentelemetry-c-wrapper
  https://github.com/open-telemetry/opentelemetry-cpp

Build options:

  USE_OTEL     - enable the OpenTelemetry filter
  OTEL_DEBUG   - compile the filter in debug mode
  OTEL_INC     - force the include path to the C wrapper
  OTEL_LIB     - force the library path to the C wrapper
  OTEL_RUNPATH - add the C wrapper RUNPATH to the executable

Example build with OTel and debug enabled:

  make -j8 USE_OTEL=1 OTEL_DEBUG=1 TARGET=linux-glibc

7 days agoBUG/MINOR: xprt_qstrm: do not parse record length on read again
Amaury Denoyelle [Mon, 13 Apr 2026 06:47:01 +0000 (08:47 +0200)] 
BUG/MINOR: xprt_qstrm: do not parse record length on read again

conn_recv_qstrm() may be called several times per connection if the read
data is too short and a truncated record is received.

Previously, record length was parsed every time the function is invoked.
However, this must only be performed if record length varint is
incomplete. Once read and parsed, data are removed from the buffer via
b_quic_dec_int(). Thus, next conn_recv_qstrm() run will reread an
invalid record length this time.

This patch fixes this by only parsing record length if <rxrlen> member
is null. Prior to it, parsing of QMux transport parameters would fail in
case of a first truncated read, which would prevent the connection
initialization.

No need to backport.

7 days agoBUG/MINOR: mux_quic: prevent QMux crash on qcc_io_send() error path
Amaury Denoyelle [Fri, 10 Apr 2026 08:37:09 +0000 (10:37 +0200)] 
BUG/MINOR: mux_quic: prevent QMux crash on qcc_io_send() error path

A QCC connection may be flagged with QC_CF_ERRL to trigger a
CONNECTION_CLOSE emission. However, for now error reporting is not
functional with QMux, as it relies on quic_conn layer access.

To prevent a crash in qcc_io_send() when using QMux, add a
conn_is_quic() check when QC_CF_ERRL is set to ensure no access will be
performed on quic_conn layer. In the future, this should be extended so
that QMux is also able to emit CONNECTION_CLOSE for connection closure.

No need to backport.

10 days agoBUG/MEDIUM: haterm: Properly initialize the splicing support for haterm
Christopher Faulet [Fri, 10 Apr 2026 14:16:38 +0000 (16:16 +0200)] 
BUG/MEDIUM: haterm: Properly initialize the splicing support for haterm

First, we must not emit any warning if splicing is not configured and the
global maxpipes value is 0. Then we must not remove GTUNE_USE_SPLICE flag
when we fail to allocate the haterm master pipe. Instead, we test it when we
negociate with the opposite side, to properly exclude the splicing if it is
not usable.

No backport needed.

10 days agoRevert "BUG/MEDIUM: haterm: Move all init functions of haterm in haterm_init.c"
Christopher Faulet [Fri, 10 Apr 2026 13:50:41 +0000 (15:50 +0200)] 
Revert "BUG/MEDIUM: haterm: Move all init functions of haterm in haterm_init.c"

This reverts commit 8056117e988a3fde05d46ecc71b2d1a3d802977d.

Moving haterm init from haproxy is not the right way to fix the issue
because it should be possible to use a haterm configuration in haproxy.

So let's revert the commit above.

10 days agoBUG/MINOR: do not crash on QMux reception of BLOCKED frames
Amaury Denoyelle [Fri, 10 Apr 2026 08:28:23 +0000 (10:28 +0200)] 
BUG/MINOR: do not crash on QMux reception of BLOCKED frames

Add QUIC BLOCKED frames in the list of supported types in
qstrm_parse_frm(). Nothing is really implemented for them as for QUIC,
but this prevents a crash when receiving one of them via QMux.

No need to backport.

10 days agoDOC: update draft link for QMux protocol
Amaury Denoyelle [Wed, 8 Apr 2026 12:47:26 +0000 (14:47 +0200)] 
DOC: update draft link for QMux protocol

QMux draft 01 support is mostly achieved thanks to the recent
implementation of the Record layer. This patch thus updates the link in
the documentation to the validated draft version.

10 days agoMEDIUM: mux-quic/xprt_qstrm: implement QMux record emission
Amaury Denoyelle [Wed, 8 Apr 2026 08:33:10 +0000 (10:33 +0200)] 
MEDIUM: mux-quic/xprt_qstrm: implement QMux record emission

This patch implements emission of the new Record layer for QMux frames.
This handles mux-quic and xprt_qstrm layers as this is performed
similarly in both cases.

Currently, the simplest approach has been prefered : each frame is
encoded in its own record. This is not the most efficient in size but it
is extremely simple to implement for a first interop testing.

10 days agoMEDIUM: xprt_qstrm: implement QMux record parsing
Amaury Denoyelle [Wed, 8 Apr 2026 12:13:05 +0000 (14:13 +0200)] 
MEDIUM: xprt_qstrm: implement QMux record parsing

This patch implements the new QMux record layer parsing for xprt_qstrm.
This is mostly similar to the MUX code from the previous patch.

Along with this change, a new xprt_qstrm layer accessor exposes the
possible remaining record length after Transport parameters parsing.
This can only occur when xprt_qstrm Rx buffer is not completely emptied
due to other following frames. If stored in the same record, MUX layer
has to know the remaining record length.

Thus, xprt_qstrm_rxrlen() is now used in qmux_init() to preinitialize
<rx.rlen> QCC field.

10 days agoMEDIUM: mux-quic: implement QMux record parsing
Amaury Denoyelle [Wed, 8 Apr 2026 08:31:57 +0000 (10:31 +0200)] 
MEDIUM: mux-quic: implement QMux record parsing

This is the first patch of a serie which aims to support the new Record
layer defined by the draft 01 of QMux protocol.

  https://www.ietf.org/archive/id/draft-ietf-quic-qmux-01.html#name-qmux-records

This patch deals with QMux reception at the MUX layer. The function
qcc_qstrm_recv() is adapted to read record headers before frame parsing.
This requires to keep the last record length read in a new QCC field
named <rx.rlen>.

Frames are only parsed once a full record is received. One of the
advantage of the record layer is that it can only contains whole frame
without truncation.

10 days agoMINOR: xprt_qstrm: handle connection errors
Amaury Denoyelle [Wed, 8 Apr 2026 11:54:47 +0000 (13:54 +0200)] 
MINOR: xprt_qstrm: handle connection errors

This patch implements proper connection error handling for xprt_qstrm
layer. Basically, processing is interrupted if CO_FL_ERROR is
encountered after either rcv_buf or snd_buf operations. Connectionn
error is set to the newly defined value CO_ER_QSTRM.

10 days agoMINOR: xprt_qstrm: implement Tx buffering
Amaury Denoyelle [Wed, 8 Apr 2026 08:42:44 +0000 (10:42 +0200)] 
MINOR: xprt_qstrm: implement Tx buffering

This commit adds buffering on transmission for xprt_qstrm layer. This is
necessary in the rare case where send syscall only emits partial data.

A new <txbuf> member is defined in xprt_qstrm context. On first send
invokation, buffer is allocated and then the QMux transport parameters
frame is encoded. Then emission is performed via snd_buf and each time
the send function is invoked.

10 days agoMINOR: xprt_qstrm/mux-quic: handle extra QMux frames after params
Amaury Denoyelle [Fri, 10 Apr 2026 07:40:10 +0000 (09:40 +0200)] 
MINOR: xprt_qstrm/mux-quic: handle extra QMux frames after params

Layer xprt_qstrm is responsible to read the initial QMux transport
parameters frame. However, it could receive more data if some other
frames follow it. This extra content can only be handled by the MUX
layer once initialized.

Theorically, it could have been implemented via MSG_PEEK. However, this
flag is currently ignored by SSL layer. Besides, it is tedious to
implement safely. A new approach has been prefered where the MUX layer
is responsible to retrieve remaining data via xprt_qstrm_rxbuf()
accessor function during its initialization.

Thus, qmux_init() now may retrieve the buffer from xprt_qstrm layer.
This is performed via b_xfer() which will result in a zero copy
transfer. If this happens, tasklet is immediately scheduled to start
demuxing.

10 days agoMINOR: xprt_qstrm: implement Rx buffering
Amaury Denoyelle [Tue, 7 Apr 2026 13:19:47 +0000 (15:19 +0200)] 
MINOR: xprt_qstrm: implement Rx buffering

Implement buffering for reception on xprt_qstrm layer. This is necessary
to handle reception of a truncated QMux transport parameters frame.

This is performed via a new dedicated <rxbuf> member in xprt_qstrm
context. Read is performed by reusing the buffer until a whole frame can
be read.

10 days agoBUG/MINOR: quic: increment pos pointer on QMux transport params parsing
Amaury Denoyelle [Wed, 8 Apr 2026 08:32:17 +0000 (10:32 +0200)] 
BUG/MINOR: quic: increment pos pointer on QMux transport params parsing

QUIC frame parsers functions take a <pos> pointer as input argument for
the data to be parsed. If parsing is successful, <pos> must be
incremented to point to the next data.

Increment was not performed when parsing QMux transport parameters
frame. This commit fixes this. Note that for now there is no real issue
as xprt_qstrm does not check the QMux frame length.

No need to backport.

10 days agoBUG/MINOR: mux-quic: fix potential NULL deref on qcc_release()
Amaury Denoyelle [Wed, 8 Apr 2026 12:58:08 +0000 (14:58 +0200)] 
BUG/MINOR: mux-quic: fix potential NULL deref on qcc_release()

In qcc_release(), <conn> may be NULL. Thus every access on it must be
tested.

With recent QMux introduction, a call to conn_is_quic() has been added
prior to registration of the stream rejection callback. It could lead to
NULL deref as <conn> is not tested there. Fix this by adding an extra
check on the pointer validity.

No need to backport.

10 days agoBUG/MINOR: hlua: fix use-after-free of HTTP reason string
Greg Kroah-Hartman [Thu, 9 Apr 2026 11:06:44 +0000 (13:06 +0200)] 
BUG/MINOR: hlua: fix use-after-free of HTTP reason string

hlua_applet_http_status() stored the result of luaL_optlstring()
directly in http_ctx->reason. The pointer references Lua-managed
string storage which is only guaranteed valid until the C function
returns to Lua. If the GC runs between applet:set_status(200, str)
and applet:start_response(), the pointer dangles.

hlua_applet_http_send_response() then calls ist(http_ctx->reason)
which does strlen() on freed memory, followed by memcpy into the
HTX status line. The freed-and-reallocated chunk contents are sent
verbatim to the HTTP client.

Trigger:

    applet:set_status(200, table.concat({"Reason ", str:rep(50)}))
    collectgarbage("collect"); collectgarbage("collect")
    applet:start_response()

With heap grooming, adjacent allocation contents (session data, TLS
material from the same thread) leak into the response status line.

Anchor the Lua string in the registry keyed by the http_ctx field
address so it survives until the applet is done with it. The
registry entry is overwritten on each call (handles repeated
set_status) and naturally cleaned up when the lua_State is closed.

This patch should be backported to all stable versions.

10 days agoBUG/MEDIUM: mux-fcgi: prevent record-length truncation with large bufsize
Greg Kroah-Hartman [Thu, 9 Apr 2026 11:06:46 +0000 (13:06 +0200)] 
BUG/MEDIUM: mux-fcgi: prevent record-length truncation with large bufsize

FCGI content_length is a 16-bit field but fcgi_set_record_size()
is called with size_t/uint32_t arguments. With tune.bufsize >= 65544
(legal; cfgparse-global.c only enforces <= INT_MAX-16), a single
HTX DATA block or accumulated outbuf can exceed 65535 bytes. The
implicit conversion to uint16_t silently truncates the length field
while b_add(mbuf, outbuf.data) writes the full body.

A client posting ~99000 bytes can craft the body so that bytes
after the truncated length are parsed by PHP-FPM as fresh FCGI
records on the connection: a smuggled BEGIN_REQUEST + PARAMS with
arbitrary SCRIPT_FILENAME / PHP_VALUE bypasses all haproxy ACLs.

Fix the zero-copy path by refusing it when the block exceeds 65535
bytes (falls through to copy). Fix the copy path by capping
outbuf.size to 65535 + header so the data-fill loop naturally
stops at the FCGI maximum and emits the rest in a subsequent record.

The PARAMS path at line 2084 is similarly affected but harder to
trigger (requires combined header+param size > 65535) and is
covered by the same outbuf.size cap pattern if applied there.

This patch must be backported to all stable versions.

10 days agoBUG/MINOR: sample: fix info leak in regsub when exp_replace fails
Greg Kroah-Hartman [Thu, 9 Apr 2026 11:06:43 +0000 (13:06 +0200)] 
BUG/MINOR: sample: fix info leak in regsub when exp_replace fails

exp_replace() returns int and returns -1 when the back-reference
expansion overflows the output buffer (regex.c:51). output->data is
size_t, so -1 becomes SIZE_MAX. There was no error check.

The subsequent comparisons interpret SIZE_MAX as a huge length:
"output->data > b_room(trash)" tries to grow trash, then
"max > output->data" is false so max stays at trash->size, and
memcpy(trash, output->area, trash->size) copies the full chunk.
output->area is a pool_alloc()'d chunk that is NOT zeroed; the
bytes after the partial exp_replace output are stale data from a
prior pool user (request headers, response bodies from the same
worker thread).

Trigger with a backreference whose expansion exceeds bufsize:

    http-request set-header X %[req.hdr(In),regsub('(.+)','\1\1')]

and a request with In: of ~9000 bytes. The X header sent to the
backend then contains ~9KB of stale heap data.

With tune.bufsize.large set, get_larger_trash_chunk() upgrades trash
and the memcpy reads up to ~50KB past the (smaller) output->area
allocation.

http_ana.c:2728 and http_act.c:551 already check exp_replace() for
-1; this call site was missed when backreferences were added.

This patch must be backported to all stable versions.

11 days agoBUG/MEDIUM: samples: Fix handling of SMP_T_METH samples
Christopher Faulet [Thu, 9 Apr 2026 19:00:00 +0000 (21:00 +0200)] 
BUG/MEDIUM: samples: Fix handling of SMP_T_METH samples

Samples of type SMP_T_METH were not properly handled in smp_dup(),
smp_is_safe() and smp_is_rw(). For "other" methods, for instance PATCH, a
fallback was performed on the SMP_T_STR type. Only the buffer considered
changed. "smp->data.u.meth.str" should be used for the SMP_T_METH samples
while smp->data.u.str should be used for SMP_T_STR samples. However, in
smp_dup(), the result was stored in wrong buffer, the string one instead of
the method one. In smp_is_safe() and smp_is_rw(), the method buffer was not
used at all.

We now take care to use the right buffer.

This patch must be backported to all stable versions.

11 days agoBUG/MINOR: haterm: Return the good start-line for 100-continue interim message
Christopher Faulet [Thu, 9 Apr 2026 18:49:23 +0000 (20:49 +0200)] 
BUG/MINOR: haterm: Return the good start-line for 100-continue interim message

When "Expect" header was found in request headers, "HTTP/1.1 100-continue"
was returned instead of "HTTP/1.1 100 continue". Let's fix it.

No backport needed.

11 days agoBUG/MINOR: http-act: validate decoded lengths in *-headers-bin
Greg Kroah-Hartman [Thu, 9 Apr 2026 11:06:45 +0000 (13:06 +0200)] 
BUG/MINOR: http-act: validate decoded lengths in *-headers-bin

http_action_set_headers_bin() decodes varint name and value lengths
from a binary sample but never validates that the decoded length
fits in the remaining sample data before constructing the ist.

If the value's varint decodes to a large number with only a few
bytes following, v.len exceeds the buffer and http_add_header()
memcpys past the sample, copying adjacent heap data into a header
sent to the backend (or client, with http-response).

The intended source for this action is the hdrs_bin sample fetch
which produces well-formed output, but nothing prevents an admin
from feeding it req.body or another untrusted source. With:

    http-request set-var(txn.h) req.body
    http-request add-headers-bin var(txn.h)

a POST body of [05]"X-Foo"[c8]"AB" produces v = {ptr="AB", len=200}
and 198 bytes of adjacent heap data go into X-Foo.

http_action_del_headers_bin() was fixed too.

Compare spoe_decode_buffer() which has the equivalent check.
Validate both name and value lengths against remaining data.

No backport needed.

11 days agoBUG/MINOR: spoe: fix pointer arithmetic overflow in spoe_decode_buffer()
Greg Kroah-Hartman [Thu, 9 Apr 2026 11:06:42 +0000 (13:06 +0200)] 
BUG/MINOR: spoe: fix pointer arithmetic overflow in spoe_decode_buffer()

decode_varint() has no iteration cap and accepts varints decoding to
any uint64_t value. When sz is large enough that p + sz wraps modulo
2^64, the check "p + sz > end" passes, *buf is set to the wrapped
pointer, and the caller's parsing loop continues from an arbitrary
relative offset before the demux buffer.

A malicious SPOE agent sending an AGENT_HELLO frame with a key-name
length varint of 0xfffffffffffff000 causes spop_conn_handle_hello()
to dereference memory ~64KB before the dbuf allocation, resulting in
SIGSEGV (DoS) or, if the read lands on live heap data, parser
confusion. The relative offset is fully attacker-controlled and
ASLR-independent.

Compare against the remaining length instead of computing p + sz.
Since p <= end is guaranteed after a successful decode_varint(),
end - p is non-negative.

This patch must be backport to all stable versions.

11 days agoBUG/MINOR: resolvers: fix memory leak on AAAA additional records
Greg Kroah-Hartman [Thu, 9 Apr 2026 11:06:41 +0000 (13:06 +0200)] 
BUG/MINOR: resolvers: fix memory leak on AAAA additional records

Commit c84c15d3938a ("BUG/MINOR: resolvers: Apply dns-accept-family
setting on additional records") converted a switch statement to an
if/else chain but left the break; in the AAAA branch. In the new
form, break exits the surrounding for loop instead of a switch case.

For every AAAA additional record in an SRV response:
  - answer_record allocated at line 1460 is never freed and never
    inserted into answer_tree -> ~580 bytes leaked per response
  - all subsequent additional records in the response are silently
    discarded

A DNS server controlling SRV responses for haproxy service discovery
can leak memory at MB/min rates given default resolution intervals.
Also breaks IPv6 SRV target resolution outright since the AAAA record
is leaked rather than attached to its SRV entry.

11 days agoREGTESTS: lua: add tune.lua.openlibs to all Lua reg-tests
William Lallemand [Tue, 7 Apr 2026 15:01:36 +0000 (17:01 +0200)] 
REGTESTS: lua: add tune.lua.openlibs to all Lua reg-tests

Ensure that all Lua regression tests exercise the restricted library
mode by setting "tune.lua.openlibs none" in their global section.

Only txn_get_priv-thread.vtc requires "string,table"

11 days agoMINOR: lua: add tune.lua.openlibs to restrict loaded Lua standard libraries
William Lallemand [Tue, 7 Apr 2026 15:01:35 +0000 (17:01 +0200)] 
MINOR: lua: add tune.lua.openlibs to restrict loaded Lua standard libraries

HAProxy has always called luaL_openlibs() unconditionally, which opens
all standard Lua libraries including io, os, package and debug. This
makes it impossible to prevent Lua scripts from executing binaries
(os.execute, io.popen), loading native C modules (package/require), or
bypassing any Lua-level sandbox via the debug library.

Add a new global directive tune.lua.openlibs that accepts a comma-separated
list of library names to load:

  tune.lua.openlibs none                   # only base + coroutine
  tune.lua.openlibs string,math,table,utf8 # safe libs only
  tune.lua.openlibs all                    # default, same as before

The base and coroutine libraries are always loaded regardless: base provides
core Lua functions that HAProxy relies on, and coroutine is required because
HAProxy overrides coroutine.create() with its own safe implementation.

When all libraries are enabled (the default), the fast path still calls
luaL_openlibs() directly with no overhead. A parse error is returned if
the directive appears after lua-load or lua-load-per-thread (the Lua state
is already initialised at that point), or if 'none' is combined with other
library names. Note that fork() and new thread creation are already blocked
by default regardless of this setting (see "insecure-fork-wanted").

12 days agoBUG/MAJOR: slz: always make sure to limit fixed output to less than worst case literals
Willy Tarreau [Wed, 8 Apr 2026 15:53:24 +0000 (17:53 +0200)] 
BUG/MAJOR: slz: always make sure to limit fixed output to less than worst case literals

Literals are sent in two ways:
  - in EOB state, unencoded and prefixed with their length
  - in FIXED state, huffman-encoded

And references are only sent in FIXED state.

The API promises that the amount of data will not grow by more than
5 bytes every 65535 input bytes (the comment was adjusted to remind
this last point). This is guaranteed by the literal encoding in EOB
state (BT, LEN, NLEN + bytes), which is supposed to be the worst
case by design.

However, as reported by Greg KH, this is currently not true: the test
that decides whether or not to switch to FIXED state to send references
doesn't properly account for the number of bytes needed to roll back
to the *exact* same state in EOB, which means sending EOB, BT,
alignment, LEN and NLEN in addition to the referenced bytes, versus
sending the encoding for the reference. By not taking into account the
cost of returning to the initial state (BT+LEN+NLEN), it was possible
to stay too long in the FIXED state and to consume the extra bytes that
are needed to return to the EOB state, resulting in producing much more
data in case of multiple switchovers (up to 6.25% increase was measured
in tests, or 1/16, which matches worst case estimates based on the code).

And this check is only valid when starting from EOB (in order to restore
the same state that offers this guarantee). When already in FIXED state,
the encoded reference is always smaller than or same size as the data.
The smallest match length we support is 4 bytes, and when encoded this
is no more than 28 bits, so it is safe to stay in FIXED state as long
as needed while checking the possibility of switching back to EOB.

This very slightly reduces the compression ratio (-0.17% on a linux
kernel source) but makes sure we respect the API promise of no more
than 5 extra bytes per 65535 of input. A side effect of the slightly
simpler check is an ~7.5% performance increase in compression speed.

Many thanks to Greg for the detailed report allowing to reproduce
the issue.

This is libslz upstream commit 002e838935bf298d967f670036efa95822b6c84e.

Note: in haproxy's default configuration (tune.bufsize 16384,
tune.maxrewrite 1024), this problem cannot be triggered, because the
reserve limits input to 15360 bytes, and the overflow is maximum
960 bytes resulting in 16320 bytes total, which still fits into the
buffer. However, reducing tune.maxrewrite below 964, or tune.bufsize
above 17408 can result in overflows for specially crafted patterns.

A workaround for larger buffers consists in always setting tune.bufsize
to at least 1/16 of tune.bufsize.

Reported-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://www.mail-archive.com/haproxy@formilux.org/msg46837.html
12 days agoMEDIUM: check: Revamp the way the protocol and xprt are determined
Olivier Houchard [Wed, 8 Apr 2026 14:05:28 +0000 (16:05 +0200)] 
MEDIUM: check: Revamp the way the protocol and xprt are determined

Storing the protocol directly into the check was not a good idea,
because the protocol may not be determined until after a DNS resolution
on the server, and may even change at runtime, if the DNS changes.
What we can, however, figure out at start up, is the net_addr_type,
which will contain all that we need to find out which protocol to use
later.
Also revert the changes made by commit 07edaed1918a6433126b4d4d61b7f7b0e9324b30
that would not reuse the server xprt if a different alpn is set for
checks. The alpn is just a string, and should not influence the choice
of the xprt.
We'll now make sure to use the server xprt, unless an address is
provided, in which case we'll use whatever xprt matches that address, or
a port, in which case we'll assume we want TCP, and use check_ssl to
know whetver we want the SSL xprt or not.
Now that the check contains all that is needed to know which protocol to
look up, always just use that when creating a new check connection if it
is the default check connection, and for now, always use TCP when a
tcp-check or http-check connect rule is used (which means those can't be
used for QUIC so far).

This should hopefully fix github issue #3324.

12 days agoMINOR: tools: Implement net_addr_type_is_quic()
Olivier Houchard [Wed, 8 Apr 2026 16:22:50 +0000 (18:22 +0200)] 
MINOR: tools: Implement net_addr_type_is_quic()

Implement net_addr_type_is_quic(), that returns 1 if the provided
net_addr_type looks like it is using QUIC, and 0 otherwise.

12 days agoMEDIUM: connections: Really enforce mux protocol requirements
Olivier Houchard [Wed, 8 Apr 2026 14:02:06 +0000 (16:02 +0200)] 
MEDIUM: connections: Really enforce mux protocol requirements

Commit 1b0dfff552713274b95c81594b153104e215ec81 attempted to make it so
the mux would expect a QUIC-like protocol or not, however it only made
that we would not instantiate a non-QUIC mux on a QUIC protocol, but not
that we tried to instance a QUIC mux on a non-QUIC protocol, so fix
that.

12 days agoCI: github: add the architecture to the cache key for vtest2 20260427-vtest2-failure flx04/20260427-vtest2-failure
William Lallemand [Wed, 8 Apr 2026 09:16:59 +0000 (11:16 +0200)] 
CI: github: add the architecture to the cache key for vtest2

ARM runners can't use the same build as the other x86_64 ones, add the
architecture to the cache key so it caches and gets the right one.

12 days agoCI: github: fix vtest path to allow correct caching
William Lallemand [Wed, 8 Apr 2026 08:38:31 +0000 (10:38 +0200)] 
CI: github: fix vtest path to allow correct caching

The vtest binary does not seem to be cached correctly by actions/cache,
the cause of the problem seems to be the binary is installed outside the
github workspace. This patch installs the binary in ~/vtest/ to fix the
issue.

12 days agoRevert "BUG: hlua: fix stack overflow in httpclient headers conversion"
William Lallemand [Wed, 8 Apr 2026 08:41:54 +0000 (10:41 +0200)] 
Revert "BUG: hlua: fix stack overflow in httpclient headers conversion"

This reverts commit a03120e228abc654d1f0d5bcb0240c6972721735.

A WIP version of the patch was applied before the actual patch by
accident. The correct patch is 2db801c ("BUG/MINOR: hlua: fix stack
overflow in httpclient headers conversion")

12 days agoCI: github: update to cache@v5
William Lallemand [Wed, 8 Apr 2026 08:14:13 +0000 (10:14 +0200)] 
CI: github: update to cache@v5

github complains about cache@v4:

Node.js 20 actions are deprecated. The following actions are running on
Node.js 20 and may not work as expected: actions/cache@v4. Actions will
be forced to run with Node.js 24 by default starting June 2nd, 2026.
Node.js 20 will be removed from the runner on September 16th, 2026.
Please check if updated versions of these actions are available that
support Node.js 24. To opt into Node.js 24 now, set the
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true environment variable on the
runner or in your workflow file. Once Node.js 24 becomes the default,
you can temporarily opt out by setting
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true. For more information see:
https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/

12 days agoBUG/MEDIUM: connection: Wake the stconn on error when failing to create mux
Christopher Faulet [Wed, 8 Apr 2026 06:07:14 +0000 (08:07 +0200)] 
BUG/MEDIUM: connection: Wake the stconn on error when failing to create mux

When the app_ops were removed, direct calls to the SC wake callback function
were replaced by tasklet wakeups. However, in conn_create_mux(), it was
replaced by a direct call to sc_conn_process(). However, sc_conn_process()
is only usable when the SC is attach to a stream. A backend mux can be
created for a healcheck. In this context, sc_conn_process() cannot be
called.

Because of this bug, crashes can be experienced when an error is triggered
during a SSL connection attempt from a healthcheck.

To fix the issue, the call to sc_conn_process() was replaced by a tasklet
wakeup.

This patch should fix the issue #3326. No backport needed.

13 days agoCI: VTest build with git clone + cache
William Lallemand [Tue, 7 Apr 2026 16:05:14 +0000 (18:05 +0200)] 
CI: VTest build with git clone + cache

The VTest2 tarball URL at code.vinyl-cache.org/vtest/VTest2/archive/main.tar.gz
no longer works. Switch scripts/build-vtest.sh to use a git clone of the
repository instead.

Add a cache step in the setup-vtest CI action so VTest is only rebuilt
when its HEAD commit changes, keyed on the runner OS and the VTest2 HEAD
SHA.

13 days agoBUG/MINOR: peers: fix OOB heap write in dictionary cache update
Greg Kroah-Hartman [Tue, 7 Apr 2026 07:48:06 +0000 (09:48 +0200)] 
BUG/MINOR: peers: fix OOB heap write in dictionary cache update

When a peer sends a dictionary entry update with a value (the else
branch at line 2109), the entry id decoded from the wire was never
validated against dc->max_entries before being used as an array index
into dc->rx[].

A malicious peer can send id=N where N > 128 (PEER_STKT_CACHE_MAX_ENTRIES)
to:
  - dc->rx[id-1].de at line 2123: OOB read followed by atomic decrement
    and potential free of an attacker-controlled pointer via
    dict_entry_unref()
  - dc->rx[id-1].de = de at line 2124: OOB write of a heap pointer at
    an attacker-controlled offset (16-byte stride, ~64 GiB range)

The bounds check was added to the key-only branch in commit f9e51beec
("BUG/MINOR: peers: Do not ignore a protocol error for dictionary
entries.") but was never added to the with-value branch. The bug has
been present since dictionary support was introduced in commit
8d78fa7def5c ("MINOR: peers: Make peers protocol support new
"server_name" data type.").

Reachable from any TCP client that knows the configured peer name
(no cryptographic authentication on the peers protocol). Requires a
stick-table with "store server_key" in the configuration.

Fix by hoisting the bounds check above the branch so it covers both
paths.

Must be backported as far as 2.6.

13 days agoBUG/MEDIUM: chunk: fix infinite loop in get_larger_trash_chunk()
Greg Kroah-Hartman [Tue, 7 Apr 2026 07:48:11 +0000 (09:48 +0200)] 
BUG/MEDIUM: chunk: fix infinite loop in get_larger_trash_chunk()

When the input chunk is already the large buffer (chk->size ==
large_trash_size), the <= comparison still matched and returned
another large buffer of the same size. Callers that retry on a
non-NULL return value (sample.c:4567 in json_query) loop forever.

The json_query infinite loop is trivially triggered: mjson_unescape()
returns -1 not only when the output buffer is too small but also for
any \uXXYY escape where XX != "00" (mjson.c:305) and for invalid
escapes like \q. The retry loop assumes -1 always means "grow the
buffer", so a 14-byte JSON body of {"k":"\u0100"} hangs the worker
thread permanently. Send N such requests to exhaust all worker
threads.

Use < instead of <= so a chunk that is already large yields NULL.
This also fixes the json converter overflow at sample.c:2869 where
no recheck happens after the "growth" returned a same-size buffer.

Introduced in commit ce912271db4e ("MEDIUM: chunk: Add support for
large chunks"). No backport needed.

13 days agoBUG/MEDIUM: chunk: fix typo allocating small trash with bufsize_large
Greg Kroah-Hartman [Tue, 7 Apr 2026 07:48:10 +0000 (09:48 +0200)] 
BUG/MEDIUM: chunk: fix typo allocating small trash with bufsize_large

A copy-paste error in alloc_trash_buffers_per_thread() passes
global.tune.bufsize_large to alloc_small_trash_buffers() instead of
global.tune.bufsize_small. This sets small_trash_size = bufsize_large.

When tune.bufsize.large is configured, get_larger_trash_chunk() then
incorrectly matches a large buffer against small_trash_size at line
169 and "grows" it to a regular (smaller) buffer. b_xfer() at line
179 attempts to copy the large buffer's contents into the smaller one:

  - Default builds (DEBUG_STRICT=1): BUG_ON in __b_putblk() aborts
    the process -> remote DoS
  - DEBUG_STRICT=0 builds: BUG_ON becomes ASSUME() and the compiler
    elides the check -> heap overflow with attacker-controlled bytes

Reachable via the json converter (sample.c:2862) when escaping
~bufsize_large/6 control characters in attacker-supplied data such
as a request header or body.

Introduced in commit 92a24a4e875b ("MEDIUM: chunk: Add support for
small chunks"). No backport needed.

13 days agoBUG/MINOR: hlua: fix format-string vulnerability in Patref error path
Greg Kroah-Hartman [Tue, 7 Apr 2026 07:48:13 +0000 (09:48 +0200)] 
BUG/MINOR: hlua: fix format-string vulnerability in Patref error path

hlua_error() is a printf-family function (calls vsnprintf), but
hlua_patref_set, hlua_patref_add, and _hlua_patref_add_bulk pass
errmsg directly as the format string. errmsg is built by pattern.c
helpers that embed the user-supplied key or value verbatim, e.g.
pat_ref_set_elt() generates "unable to parse '<value>'".

A Lua script calling:

    ref:set("key", "%p.%p.%p.%p.%p.%p.%p.%p")

against a map with an integer output type (where the parse fails)
gets stack/register contents formatted into the (nil, err) return
value -> ASLR/canary leak. With %n and no _FORTIFY_SOURCE this
becomes an arbitrary write primitive.

This must be backported as far as the Patref Lua API exists.

13 days agoBUG/MINOR: hlua: fix stack overflow in httpclient headers conversion
Greg Kroah-Hartman [Tue, 7 Apr 2026 07:48:07 +0000 (09:48 +0200)] 
BUG/MINOR: hlua: fix stack overflow in httpclient headers conversion

hlua_httpclient_table_to_hdrs() declares a VLA of size
global.tune.max_http_hdr (default 101) on the stack but never checks
hdr_num against that bound. A Lua script that supplies a header table
with more than 101 values writes struct http_hdr entries (two ist =
two heap pointers + two lengths) past the end of the VLA, smashing
the stack frame.

Trigger from any Lua action/task/service:

    local hc = core.httpclient()
    local v = {}
    for i = 1, 300 do v[i] = "x" end
    hc:get{ url = "http://127.0.0.1/", headers = { ["X"] = v } }

Each out-of-bounds entry writes a heap pointer (controllable
allocation contents via istdup) plus an attacker-chosen length onto
the stack, overwriting the saved return address.

[wla: this is only reachable if the Lua script passes more than
max_http_hdr header values, which requires access to the script itself]

This must be backported as far as the httpclient Lua API exists.

Signed-off-by: William Lallemand <wlallemand@haproxy.com>
13 days agoBUG: hlua: fix stack overflow in httpclient headers conversion
Greg Kroah-Hartman [Tue, 7 Apr 2026 07:48:07 +0000 (09:48 +0200)] 
BUG: hlua: fix stack overflow in httpclient headers conversion

hlua_httpclient_table_to_hdrs() declares a VLA of size
global.tune.max_http_hdr (default 101) on the stack but never checks
hdr_num against that bound. A Lua script that supplies a header table
with more than 101 values writes struct http_hdr entries (two ist =
two heap pointers + two lengths) past the end of the VLA, smashing
the stack frame.

Trigger from any Lua action/task/service:

    local hc = core.httpclient()
    local v = {}
    for i = 1, 300 do v[i] = "x" end
    hc:get{ url = "http://127.0.0.1/", headers = { ["X"] = v } }

Each out-of-bounds entry writes a heap pointer (controllable
allocation contents via istdup) plus an attacker-chosen length onto
the stack, overwriting the saved return address. With no stack
canary, this is direct RCE; with a canary, it requires a leak first.

Reachable from any deployment that loads Lua scripts. While Lua
scripts are nominally trusted, this turns "can edit Lua" into "can
execute arbitrary native code", which is a meaningful boundary in
many setups (Lua sandbox escape).

This must be backported as far as the httpclient Lua API exists.

13 days agoBUG/MEDIUM: jwe: fix memory leak in jwt_decrypt_secret with var argument
Greg Kroah-Hartman [Tue, 7 Apr 2026 07:48:15 +0000 (09:48 +0200)] 
BUG/MEDIUM: jwe: fix memory leak in jwt_decrypt_secret with var argument

When the secret argument to jwt_decrypt_secret is a variable
(ARGT_VAR) rather than a literal string, alloc_trash_chunk() is
called to hold the base64-decoded secret but the buffer is never
released. The end: label frees input, decrypted_cek, out, and the
decoded_items array but not secret.

Each request leaks one trash chunk (~tune.bufsize, default 16KB).
At ~65000 requests per GiB this allows slow memory exhaustion DoS
against any config of the form:

    http-request set-var(txn.x) req.hdr(...),jwt_decrypt_secret(txn.key)

This must be backported as far as JWE support exists.

13 days agoBUG/MEDIUM: jwt: fix heap overflow in ECDSA signature DER conversion
Greg Kroah-Hartman [Tue, 7 Apr 2026 07:48:12 +0000 (09:48 +0200)] 
BUG/MEDIUM: jwt: fix heap overflow in ECDSA signature DER conversion

convert_ecdsa_sig() calls i2d_ECDSA_SIG(ecdsa_sig, &p) where p
points into signature->area, a trash chunk of tune.bufsize bytes
(default 16384). i2d writes with no output bound.

The raw R||S input can be up to bufsize bytes (filled by
base64urldec at jwt.c:520-527), giving bignum_len up to 8192. The
DER encoding adds a SEQUENCE header (2-4 bytes), two INTEGER headers
(2-4 bytes each), and up to two leading-zero sign-padding bytes when
the bignum high bit is set. With two 8192-byte bignums having the
high bit set, the encoding is ~16398 bytes, overflowing the 16384-
byte buffer by ~14 bytes.

Triggered by any JWT with alg=ES256/384/512 and a ~21830-character
base64url signature. The signature does not need to verify
successfully; the overflow happens before verification. Reachable
from any config using jwt_verify with an EC algorithm.

Also fixes the existing wrong check: i2d returns -1 on error which
became SIZE_MAX in the size_t signature->data, defeating the
"== 0" test.

This must be backported as far as JWT support exists.

13 days agoBUG/MEDIUM: jwe: fix NULL deref crash with empty CEK and non-dir alg
Greg Kroah-Hartman [Tue, 7 Apr 2026 07:48:09 +0000 (09:48 +0200)] 
BUG/MEDIUM: jwe: fix NULL deref crash with empty CEK and non-dir alg

In sample_conv_jwt_decrypt_secret(), when a JWE token has an empty
encrypted-key section but the algorithm is not "dir" (e.g. A128KW),
neither branch initializes decrypted_cek. The NULL pointer is then
passed to decrypt_ciphertext() which dereferences it:

  - For GCM encodings: aes_process() calls b_orig(NULL) -> SIGSEGV
  - For CBC encodings: b_data(NULL) at jwe.c:463 -> SIGSEGV

A single HTTP request with a crafted Authorization header crashes the
worker process. Trigger token (JOSE header {"alg":"A128KW","enc":"A128GCM"},
empty CEK section between the two dots):

  eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0..AAAAAAAAAAAAAAAA.AA.AA

Reachable in any configuration using the jwt_decrypt_secret converter.
The other two decrypt converters (jwt_decrypt_jwk, jwt_decrypt_cert)
already have the check.

This must be backported as far as JWE support exists.

13 days agoBUG/MEDIUM: payload: validate SNI name_len in req.ssl_sni
Greg Kroah-Hartman [Tue, 7 Apr 2026 07:48:08 +0000 (09:48 +0200)] 
BUG/MEDIUM: payload: validate SNI name_len in req.ssl_sni

The 16-bit name_len field is read directly from the ClientHello and
stored as the sample length without any validation against srv_len,
ext_len, or the channel buffer size. A 65-byte ClientHello with
name_len=0xffff produces a sample claiming 65535 bytes of data when
only ~4 bytes are actually present in the buffer.

Downstream consumers then read tens of kilobytes past the channel
buffer:
  - pattern.c:741 XXH3() hashes 65535 bytes -> ~50KB OOB heap read
  - sample.c smp_dup memcpy if large trash configured
  - log-format %[req.ssl_sni] leaks heap contents to logs/headers

Reachable pre-authentication on any TCP frontend using req.ssl_sni
(req_ssl_sni), which is the documented way to do SNI-based content
switching in TCP mode. No SSL handshake is required; the parser
runs on raw buffer contents in tcp-request content rules.

Bug introduced in commit d4c33c8889ec3 (2013). The ALPN parser in
the same file at line 1044 has the equivalent check; SNI never did.

This must be backported to all supported versions.

2 weeks agoBUG/MEDIUM: tcpcheck: Properly retrieve tcpcheck type to install the best mux
Christopher Faulet [Sun, 5 Apr 2026 07:22:11 +0000 (09:22 +0200)] 
BUG/MEDIUM: tcpcheck: Properly retrieve tcpcheck type to install the best mux

When the healthcheck section support was added, the tcpcheck type was moved
into the tcpcheck ruleset. However, conn_install_mux_chk() function was not
updated accordingly. So the TCP mode was always returned.

No backport needed. This patch is related to #3324 but it is not the root
cause of the issue.

2 weeks agoBUG/MINOR: counters: fix unexpected 127 char GUID truncation for shm-stats-file objects
Aurelien DARRAGON [Fri, 3 Apr 2026 14:12:46 +0000 (16:12 +0200)] 
BUG/MINOR: counters: fix unexpected 127 char GUID truncation for shm-stats-file objects

As reported by GH @phihos on GH #3320, using the shm-stats-file feature
with objects exceeding 127 chars would result in object name being
unexpectedly truncated, while GUID API supports up to 128 chars.

Indeed, with the config below, and shm-stats-file enabled:
   server s1  127.0.0.1:1 guid srv:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:SRV_1 disabled
    server s10 127.0.0.1:1 guid srv:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:SRV_10 disabled

haproxy would store the second server object with the same id as the first
one, but upon reload, only the first one would be restored, which would
eventually cause shm-stats-file slot exhaustion with repetitive reloads.

@phihos, found out the underlying issue, in counters.c we used snprintf()
with sizeof(shm_obj->guid) - 1 as <size> parameter, while we should have
use sizeof(shm_obj->guid) instead since shm_obj->guid already takes the
terminating NULL byte into account.

So we simply apply the fix suggested by @phihos, and hopefully this should
solve the shm-stats-file slot leak that was observed.

Unfortunately, for now, we cannot warn the user that a duplicate
shm-stats-file object was found, because we accept duplicate objects
by design for 2 reasons. The first one is for a new process to be able
to change the object type for a previously known GUID while allowing
previous processes to use the old object as long as they are alive.
The second reason is that upon startup we cannot afford to scan the
whole object list, as soon as we find a match (type + GUID), we bind
the object, and this way we avoid unnecessary lookup time.

Perhaps we have room for improvement in the future, but for now let's
keep it this way.

It should be backported to 3.3

Big thanks to @phihos for the bug description, analysis and
suggestions.

2 weeks agoBUG/MEDIUM: tcpcheck/server: Fix parsing of healthcheck param for dynamic servers
Christopher Faulet [Fri, 3 Apr 2026 14:28:08 +0000 (16:28 +0200)] 
BUG/MEDIUM: tcpcheck/server: Fix parsing of healthcheck param for dynamic servers

The parsing of the "healthcheck" parameter for dynamic servers was not
finished. The post-config was missing, leading to a crash because the
ruleset pointer was NULL.

To fix the issue, check_server_tcpcheck() function is called in
cli_parse_add_server().

No backport needed.

2 weeks agoMINOR: tcpcheck: Reject unknown keyword during parsing of healthcheck section
Christopher Faulet [Fri, 3 Apr 2026 14:26:40 +0000 (16:26 +0200)] 
MINOR: tcpcheck: Reject unknown keyword during parsing of healthcheck section

unknown keyword was just ignored. it is not really handy to detect
error. Now an error is reported and the parsing is aborted.

2 weeks agoBUG/MINOR: http-act: fix a typo in the "pause" action error message
Willy Tarreau [Fri, 3 Apr 2026 14:24:43 +0000 (16:24 +0200)] 
BUG/MINOR: http-act: fix a typo in the "pause" action error message

It was saying "mause" instead of "pause" :-)
This should be backported to 3.2.

2 weeks agoDOC: config: Fix two typos in the server param "healthcheck" description
Christopher Faulet [Fri, 3 Apr 2026 13:50:23 +0000 (15:50 +0200)] 
DOC: config: Fix two typos in the server param "healthcheck" description

There was 2 typos here. First, the 'k' was missing on the parameter name.
Then "sectino" was used in the description instead of "section". Let's fix
them.

2 weeks agoMINOR: servers: The right parameter for idle-pool.shared is "full"
Olivier Houchard [Fri, 3 Apr 2026 13:45:26 +0000 (15:45 +0200)] 
MINOR: servers: The right parameter for idle-pool.shared is "full"

In documentation, and in an error message, provide the right new keyword for
"idle-pool.shared", it is "full", not "auto".

2 weeks agoBUG/MEDIUM: mux-h1: Disable 0-copy forwarding when draining the request
Christopher Faulet [Fri, 3 Apr 2026 13:12:54 +0000 (15:12 +0200)] 
BUG/MEDIUM: mux-h1: Disable 0-copy forwarding when draining the request

When an early response is sent to the client and the H1 connection is
switched to the draining state, we must take care to disable the 0-copy data
forwarding because the backend side is no longer here. It is an issue
because this prevent any regular receive to be performed.

This patch should fix the issue #3316. It must be backported as far as 3.0.

2 weeks agoBUG/MEDIUM: haterm: Move all init functions of haterm in haterm_init.c
Christopher Faulet [Fri, 3 Apr 2026 10:20:20 +0000 (12:20 +0200)] 
BUG/MEDIUM: haterm: Move all init functions of haterm in haterm_init.c

Functions used to initialize haterm (the splicing and the response buffers)
were defined and registered in haterm.c. The problem is that this file in
compiled with haproxy. So it may be an issue. And for the splicing part,
warnings may be emitted when haproxy is started.

To avoid any issue during haproxy startup and to avoid to initialize some
part of haterm, all init functions were moved into haterm_init.c file.

No backport needed.

2 weeks agoMINOR: tcpcheck: reintroduce proxy_parse_tcpcheck() symbol
William Lallemand [Fri, 3 Apr 2026 12:35:58 +0000 (14:35 +0200)] 
MINOR: tcpcheck: reintroduce proxy_parse_tcpcheck() symbol

Remove the proxy_parse_tcpcheck() static keyword.

2 weeks agoRevert "CLEANUP: tcpcheck: Don't needlessly expose proxy_parse_tcpcheck()"
William Lallemand [Fri, 3 Apr 2026 12:15:11 +0000 (14:15 +0200)] 
Revert "CLEANUP: tcpcheck: Don't needlessly expose proxy_parse_tcpcheck()"

This reverts commit 51e1562a0d4fe7fc5b808ec952ae4f03b4a5d85f.

2 weeks agoREGTESTS: add a test for "filter-sequence" directive
Aurelien DARRAGON [Fri, 3 Apr 2026 08:51:01 +0000 (10:51 +0200)] 
REGTESTS: add a test for "filter-sequence" directive

We add a reg-test, filter_sequence.vtc, with associated lua file
dummy_filters.lua to cover the "filter-sequence" directive and
ensure it is working as expected, both for request and responses
paths.

This regtest will only be effective starting with 3.4-dev0

2 weeks agoMEDIUM: filters: add "filter-sequence" directive
Aurelien DARRAGON [Wed, 11 Mar 2026 14:37:44 +0000 (15:37 +0100)] 
MEDIUM: filters: add "filter-sequence" directive

This is another pre-requisite work for upcoming decompression filter.

In this patch we implement the "filter-sequence" directive which can be
used in proxy section (frontend,backend,listen) and takes 2 parameters

The first one is the direction (request or response), the second one
is a comma separated list of filter names previously declared on the
proxy using the "filter" keyword.

The main goal of this directive is to be able to instruct haproxy in which
order the filters should be executed on request and response paths,
especially if the ordering between request and response handling must
differ, and without relying on the filter declaration ordering (within
the proxy) which is used by default by haproxy.

Another benefit of this feature is that it becomes possible to "ignore"
a previously declared filter on the proxy. Indeed, when filter-sequence
is defined for a given direction (request/response), then it will be used
over the implicit filter ordering, but if a filter which was previously
declared is not specified in the related filter-sequence, it will not be
executed on purpose. This can be used as a way to temporarily disable a
filter without completely removing its configuration.

Documentation was updated (check examples for more info)

2 weeks agoMINOR: filters: add filter name to flt_conf struct
Aurelien DARRAGON [Tue, 31 Mar 2026 12:44:34 +0000 (14:44 +0200)] 
MINOR: filters: add filter name to flt_conf struct

flt_conf struct stores the filter id, which is used internally to check
match the filter against static pointer identifier, and also used as
descriptive text to describe the filter. But the id is not consistent
with the public name as used in the configuration (for instance when
selecting filter through the 'filter' directive).

What we do in this patch is that we add flt_conf->name member, which
stores the real filter name as seen in the configuration. This will
allow to select filters by their name from other directives in the
configuration.

2 weeks agoDOC: config: fix ambiguous info in log-steps directive description
Aurelien DARRAGON [Thu, 2 Apr 2026 17:08:30 +0000 (19:08 +0200)] 
DOC: config: fix ambiguous info in log-steps directive description

log-steps takes <steps> as parameter. <steps> is made of individual
log origins separated by commas, as shown in the examples, but the
directive's description says it should be separated by spaces, which
is wrong.

Let's fix that

It should be backported up to 3.2

2 weeks ago[RELEASE] Released version 3.4-dev8 v3.4-dev8
Willy Tarreau [Fri, 3 Apr 2026 09:46:05 +0000 (11:46 +0200)] 
[RELEASE] Released version 3.4-dev8

Released version 3.4-dev8 with the following main changes :
    - MINOR: log: split do_log() in do_log() + do_log_ctx()
    - MINOR: log: provide a way to override logger->profile from process_send_log_ctx
    - MINOR: log: support optional 'profile <log_profile_name>' argument to do-log action
    - BUG/MINOR: sock: adjust accept() error messages for ENFILE and ENOMEM
    - BUG/MINOR: qpack: fix 62-bit overflow and 1-byte OOB reads in decoding
    - MEDIUM: sched: do not run a same task multiple times in series
    - MINOR: sched: do not requeue a tasklet into the current queue
    - MINOR: sched: do not punish self-waking tasklets anymore
    - MEDIUM: sched: do not punish self-waking tasklets if TASK_WOKEN_ANY
    - MEDIUM: sched: change scheduler budgets to lower TL_BULK
    - MINOR: mux-h2: assign a limited frames processing budget
    - BUILD: sched: fix leftover of debugging test in single-run changes
    - BUG/MEDIUM: acme: fix multiple resource leaks in acme_x509_req()
    - MINOR: http_htx: use enum for arbitrary values in conf_errors
    - MINOR: http_htx: rename fields in struct conf_errors
    - MINOR: http_htx: split check/init of http_errors
    - MINOR/OPTIM: http_htx: lookup once http_errors section on check/init
    - MEDIUM: proxy: remove http-errors limitation for dynamic backends
    - BUG/MINOR: acme: leak of ext_san upon insertion error
    - BUG/MINOR: acme: wrong error when checking for duplicate section
    - BUG/MINOR: acme/cli: wrong argument check in 'acme renew'
    - BUG/MINOR: http_htx: fix null deref in http-errors config check
    - MINOR: buffers: Move small buffers management from quic to dynbuf part
    - MINOR: dynbuf: Add helper functions to alloc large and small buffers
    - MINOR: quic: Use b_alloc_small() to allocate a small buffer
    - MINOR: config: Relax tests on the configured size of small buffers
    - MINOR: config: Report the warning when invalid large buffer size is set
    - MEDIUM: htx: Add htx_xfer function to replace htx_xfer_blks
    - MINOR: htx: Add helper functions to xfer a message to smaller or larger one
    - MINOR: http-ana: Use HTX API to move to a large buffer
    - MEDIUM: chunk: Add support for small chunks
    - MEDIUM: stream: Try to use a small buffer for HTTP request on queuing
    - MEDIUM: stream: Try to use small buffer when TCP stream is queued
    - MEDIUM: stconn: Use a small buffer if possible for L7 retries
    - MEDIUM: tree-wide: Rely on htx_xfer() instead of htx_xfer_blks()
    - Revert "BUG/MEDIUM: mux-h2: make sure to always report pending errors to the stream"
    - MEDIUM: mux-h2: Stop dealing with HTX flags transfer in h2_rcv_buf()
    - MEDIUM: tcpcheck: Use small buffer if possible for healthchecks
    - MINOR: proxy: Review options flags used to configure healthchecks
    - DOC: config: Fix alphabetical ordering of proxy options
    - DOC: config: Fix alphabetical ordering of external-check directives
    - MINOR: proxy: Add use-small-buffers option to set where to use small buffers
    - DOC: config: Add missing 'status-code' param for 'http-check expect' directive
    - DOC: config: Reorder params for 'tcp-check expect' directive
    - BUG/MINOR: acme: NULL check on my_strndup()
    - BUG/MINOR: acme: free() DER buffer on a2base64url error path
    - BUG/MINOR: acme: replace atol with len-bounded __strl2uic() for retry-after
    - BUG/MINOR: acme/cli: fix argument check and error in 'acme challenge_ready'
    - BUILD: tools: potential null pointer dereference in dl_collect_libs_cb
    - BUG/MINOR: ech: permission checks on the CLI
    - BUG/MINOR: acme: permission checks on the CLI
    - BUG/MEDIUM: check: Don't reuse the server xprt if we should not
    - MINOR: checks: Store the protocol to be used in struct check
    - MINOR: protocols: Add a new proto_is_quic() function
    - MEDIUM: connections: Enforce mux protocol requirements
    - MEDIUM: server: remove a useless memset() in srv_update_check_addr_port.
    - BUG/MINOR: config: Warn only if warnif_cond_conflicts report a conflict
    - BUG/MINOR: config: Properly test warnif_misplaced_* return values
    - BUG/MINOR: http-ana: Only consider client abort for abortonclose
    - BUG/MEDIUM: acme: skip doing challenge if it is already valid
    - MINOR: connections: Enhance tune.idle-pool.shared
    - BUG/MINOR: acme: fix task allocation leaked upon error
    - BUG/MEDIUM: htx: Fix htx_xfer() to consume more data than expected
    - CI: github: fix tag listing by implementing proper API pagination
    - CLEANUP: fix typos and spelling in comments and documentation
    - BUG/MINOR: quic: close conn on packet reception with incompatible frame
    - CLEANUP: stconn: Remove usless sc_new_from_haterm() declaration
    - BUG/MINOR: stconn: Always declare the SC created from healthchecks as a back SC
    - MINOR: stconn: flag the stream endpoint descriptor when the app has started
    - MINOR: mux-h2: report glitches on early RST_STREAM
    - BUG/MINOR: net_helper: fix length controls on ip.fp tcp options parsing
    - BUILD: net_helper: fix unterminated comment that broke the build
    - MINOR: resolvers: basic TXT record implementation
    - MINOR: acme: store the TXT record in auth->token
    - MEDIUM: acme: add dns-01 DNS propagation pre-check
    - MEDIUM: acme: new 'challenge-ready' option
    - DOC: configuration: document challenge-ready and dns-delay options for ACME
    - SCRIPTS: git-show-backports: list new commits and how to review them with -L
    - BUG/MEDIUM: ssl/cli: tls-keys commands warn when accessed without admin level
    - BUG/MEDIUM: ssl/ocsp: ocsp commands warn when accessed without admin level
    - BUG/MEDIUM: map/cli: map/acl commands warn when accessed without admin level
    - BUG/MEDIUM: ssl/cli: tls-keys commands are missing permission checks
    - BUG/MEDIUM: ssl/ocsp: ocsp commands are missing permission checks
    - BUG/MEDIUM: map/cli: CLI commands lack admin permission checks
    - DOC: configuration: mention QUIC server support
    - MEDIUM: Add set-headers-bin, add-headers-bin and del-headers-bin actions
    - BUG/MEDIUM: mux-h1: Don't set MSG_MORE on bodyless responses forwarded to client
    - BUG/MINOR: http_act: Properly handle decoding errors in *-headers-bin actions
    - MEDIUM: stats: Hide the version by default and add stats-showversion
    - MINOR: backends: Don't update last_sess if it did not change
    - MINOR: servers: Don't update last_sess if it did not change
    - MINOR: ssl/log: add keylog format variables and env vars
    - DOC: configuration: update tune.ssl.keylog URL to IETF draft
    - BUG/MINOR: http_act: Make set/add-headers-bin compatible with ACL conditions
    - MINOR: action: Add a sample expression field in arguments used by HTTP actions
    - MEDIUM: http_act: Rework *-headers-bin actions
    - BUG/MINOR: tcpcheck: Remove unexpected flag on tcpcheck rules for httchck option
    - MEDIUM: tcpcheck: Refactor how tcp-check rulesets are stored
    - MINOR: tcpcheck: Deal with disable-on-404 and send-state in the tcp-check itself
    - BUG/MINOR: tcpcheck: Don't enable http_needed when parsing HTTP samples
    - MINOR: tcpcheck: Use tcpcheck flags to know a healthcheck uses SSL connections
    - BUG/MINOR: tcpcheck: Use tcpcheck context for expressions parsing
    - CLEANUP: tcpcheck: Don't needlessly expose proxy_parse_tcpcheck()
    - MINOR: tcpcheck: Add a function to stringify the healthcheck type
    - MEDIUM: tcpcheck: Split parsing functions to prepare healthcheck sections parsing
    - MEDIUM: tcpcheck:  Add parsing support for healthcheck sections
    - MINOR: tcpcheck: Extract tcpheck ruleset post-config in a dedicated function
    - MEDIUM: tcpcheck/server: Add healthcheck server keyword
    - REGTESTS: tcpcheck: Add a script to check healthcheck section
    - MINOR: acme: add 'dns-timeout' keyword for dns-01 challenge
    - CLEANUP: net_helper: fix typo in comment
    - MINOR: acme: set the default dns-delay to 30s
    - MINOR: connection: add function to identify a QUIC connection
    - MINOR: quic: refactor frame parsing
    - MINOR: quic: refactor frame encoding
    - BUG/MINOR: quic: fix documentation for transport params decoding
    - MINOR: quic: split transport params decoding/check
    - MINOR: quic: remove useless quic_tp_dec_err type
    - MINOR: quic: define QMux transport parameters frame type
    - MINOR: quic: implement QMux transport params frame parser/builder
    - MINOR: mux-quic: move qcs stream member into tx inner struct
    - MINOR: mux-quic: prepare Tx support for QMux
    - MINOR: mux-quic: convert init/closure for QMux compatibility
    - MINOR: mux-quic: protect qcc_io_process for QMux
    - MINOR: mux-quic: prepare traces support for QMux
    - MINOR: quic: abstract stream type in qf_stream frame
    - MEDIUM: mux-quic: implement QMux receive
    - MINOR: mux-quic: handle flow-control frame on qstream read
    - MINOR: mux-quic: define Rx connection buffer for QMux
    - MINOR: mux_quic: implement qstrm rx buffer realign
    - MEDIUM: mux-quic: implement QMux send
    - MINOR: mux-quic: implement qstream send callback
    - MINOR: mux-quic: define Tx connection buffer for QMux
    - MINOR: xprt_qstrm: define new xprt module for QMux protocol
    - MINOR: xprt_qstrm: define callback for ALPN retrieval
    - MINOR: xprt_qstrm: implement reception of transport parameters
    - MINOR: xprt_qstrm: implement sending of transport parameters
    - MEDIUM: ssl: load xprt_qstrm after handshake completion
    - MINOR: mux-quic: use QMux transport parameters from qstrm xprt
    - MAJOR: mux-quic: activate QMux for frontend side
    - MAJOR: mux-quic: activate QMux on the backend side
    - MINOR: acme: split the CLI wait from the resolve wait
    - MEDIUM: acme: initialize the dns timer starting from the first DNS request
    - DEBUG: connection/flags: add QSTRM flags for the decoder
    - BUG/MINOR: mux_quic: fix uninit for QMux emission
    - MINOR: acme: remove remaining CLI wait in ACME_RSLV_TRIGGER
    - MEDIUM: acme: split the initial delay from the retry DNS delay
    - BUG/MINOR: cfgcond: properly set the error pointer on evaluation error
    - BUG/MINOR: cfgcond: always set the error string on openssl_version checks
    - BUG/MINOR: cfgcond: always set the error string on awslc_api checks
    - BUG/MINOR: cfgcond: fail cleanly on missing argument for "feature"
    - MINOR: ssl: add the ssl_fc_crtname sample fetch
    - MINOR: hasterm: Change hstream_add_data() to prepare zero-copy data forwarding
    - MEDIUM: haterm: Add support for 0-copy data forwading and option to disable it
    - MEDIUM: haterm: Prepare support for splicing by initializing a master pipe
    - MEDIUM: haterm: Add support for splicing and option to disable it
    - MINOR: haterm: Handle boolean request options as flags
    - MINOR: haterm: Add an request option to disable splicing
    - BUG/MINOR: ssl: fix memory leak in ssl_fc_crtname by using SSL_CTX ex_data index

2 weeks agoBUG/MINOR: ssl: fix memory leak in ssl_fc_crtname by using SSL_CTX ex_data index
William Lallemand [Fri, 3 Apr 2026 08:58:48 +0000 (10:58 +0200)] 
BUG/MINOR: ssl: fix memory leak in ssl_fc_crtname by using SSL_CTX ex_data index

The ssl_crtname_index was registered with SSL_get_ex_new_index() but the
certificate name is stored on a SSL_CTX object via SSL_CTX_set_ex_data().
The free callback is only invoked for the object type matching the index
registration, so the strdup'd name was never freed when the SSL_CTX was
released.

Fix this by using SSL_CTX_get_ex_new_index() instead, which ensures the
free callback fires when the SSL_CTX is destroyed.

No backport needed.

2 weeks agoMINOR: haterm: Add an request option to disable splicing
Christopher Faulet [Fri, 3 Apr 2026 08:26:37 +0000 (10:26 +0200)] 
MINOR: haterm: Add an request option to disable splicing

The parameter "?S=0" can now be added on the request URI to disable the
splicing for the response. "?S=1" will only fallback on the haterm settings.

2 weeks agoMINOR: haterm: Handle boolean request options as flags
Christopher Faulet [Fri, 3 Apr 2026 08:17:39 +0000 (10:17 +0200)] 
MINOR: haterm: Handle boolean request options as flags

Following request options are now handled as flags:

  - ?k=1 => flag HS_ST_OPT_CHUNK_RES is set
  - ?c=0 => flag HS_ST_OPT_NO_CACHE is set
  - ?R=1 => flag HS_ST_OPT_RANDOM_RES is set
  - ?A=A => flag HS_ST_OPT_REQ_AFTER_RES is set.

By default, none is set.

2 weeks agoMEDIUM: haterm: Add support for splicing and option to disable it
Christopher Faulet [Thu, 2 Apr 2026 19:47:12 +0000 (21:47 +0200)] 
MEDIUM: haterm: Add support for splicing and option to disable it

The support for the splicing was added and enabled by default, if
supported. The command line option '-dS' was also added to disable the
feature.

When the splicing can be used and the front multiplexer agrees to proceed,
tee() is used to "copy" data from the master pipe to the client pipe.