Commit graph

20421 commits

Author SHA1 Message Date
Willy Tarreau
2c317cfed7 MINOR: net_helper: prepare the ip.fp() converter to support more options
It can make sense to support extra components in the fingerprint to ease
configuration, so let's change the 0/1 value to a bit field. We also turn
the current 1 (TCP options list) to 2 so that we'll reuse 1 for the TTL.
2026-01-01 10:19:20 +01:00
Willy Tarreau
e88e03a6e4 MINOR: net_helper: add ip.fp() to build a simplified fingerprint of a SYN
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
Here we collect all the stuff that depends on the sender's settings,
such as TOS, IP version, TTL range, presence of DF bit or IP options,
presence of DATA in the SYN, CWR+ECE flags, TCP header length, wscale,
initial window, mss, as well as the list of TCP extension kinds. It's
obviously fairly limited but can allows to avoid blacklisting certain
valid clients sharing the same IP address as a misbehaving one.

It supports both a short and a long mode depending on the argument.
These can be used with the tcp-ss bind option. The doc was updated
accordingly.
2025-12-31 17:17:38 +01:00
Willy Tarreau
6e46d1345b MINOR: net_helper: add sample converters to decode TCP headers
This adds the following converters, used to decode fields
in an incoming tcp header:

   tcp.dst, tcp.flags, tcp.seq, tcp.src, tcp.win,
   tcp.options.mss, tcp.options.tsopt, tcp.options.tsval,
   tcp.options.wscale, tcp.options_list,

These can be used with the tcp-ss bind option. The doc was updated
accordingly.
2025-12-31 17:17:23 +01:00
Willy Tarreau
e0a7a7ca43 MINOR: net_helper: add sample converters to decode IP packet headers
This adds a few converters that help decode parts of IP packets:
  - ip.data : returns the next header (typically TCP)
  - ip.df   : returns the dont-fragment flags
  - ip.dst  : returns the destination IPv4/v6 address
  - ip.hdr  : returns only the IP header
  - ip.proto: returns the upper level protocol (udp/tcp)
  - ip.src  : returns the source IPv4/v6 address
  - ip.tos  : returns the TOS / TC field
  - ip.ttl  : returns the TTL/HL value
  - ip.ver  : returns the IP version (4 or 6)

These can be used with the tcp-ss bind option. The doc was updated
accordingly.
2025-12-31 17:16:29 +01:00
Willy Tarreau
90d2f157f2 MINOR: net_helper: add sample converters to decode ethernet frames
This adds a few converters that help decode parts of ethernet frame
headers:
  - eth.data : returns the next header (typically IP)
  - eth.dst  : returns the destination MAC address
  - eth.hdr  : returns only the ethernet header
  - eth.proto: returns the ethernet proto
  - eth.src  : returns the source MAC address
  - eth.vlan : returns the VLAN ID when present

These can be used with the tcp-ss bind option. The doc was updated
accordingly.
2025-12-31 17:15:36 +01:00
Willy Tarreau
933cb76461 BUG/MINOR: backend: inspect request not response buffer to check for TFO
In 2.6, do_connect_server() was introduced by commit 0a4dcb65f ("MINOR:
stream-int/backend: Move si_connect() in the backend scope") and changed
the approach to work with a stream instead of a stream-interface. However
si_oc(si) was wrongly turned to &s->res instead of &s->req, which breaks
TFO by always inspecting the response channel to figure whether there are
data pending.

This fix can be backported to all versions till 2.6.
2025-12-31 13:03:53 +01:00
Willy Tarreau
799653d536 BUG/MINOR: backend: fix the conn_retries check for TFO
In 2.6, the retries counter on a stream was changed from retries left
to retries done via commit 731c8e6cf ("MINOR: stream: Simplify retries
counter calculation"). However, one comparison fell through the cracks
in order to detect whether or not we can use TFO (only first attempt),
resulting in TFO never working anymore.

This may be backported to all versions till 2.6.
2025-12-31 13:03:53 +01:00
Maxime Henrion
51592f7a09 BUG/MAJOR: set the correct generation ID in pat_ref_append().
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
This fixes crashes when creating more than one new revision of a map or
acl file and purging the previous version.
2025-12-31 00:29:47 +01:00
Olivier Houchard
54f59e4669 BUG/MEDIUM: cpu-topo: Don't forget to reset visited_ccx.
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
We want to reset visited_ccx, as introduced by commit
8aef5bec1e, each time we run the loop,
otherwise the chances of its content being correct are very low, and
will likely end up being bound to the wrong threads.
This was reported in github issue #3224.
2025-12-26 23:55:57 +01:00
Ilia Shipitsin
f8a77ecf62 CLEANUP: assorted typo fixes in the code, commits and doc
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
2025-12-25 19:45:29 +01:00
Willy Tarreau
6fb521d2f6 MINOR: tcp_sample: implement the fc_saved_syn sample fetch function
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
This function retrieves the copy of a SYN packet that the system has
kept for us when bind option "tcp-ss" was set to 1 or above. It's
recommended to copy it to a local variable because it will be freed
after being read. It allows to inspect all parts of an incoming SYN
packet, provided that it was preserved (e.g. not possible with SYN
cookies). The doc provides examples of how to use it.
2025-12-24 18:39:37 +01:00
Willy Tarreau
52d60bf9ee MINOR: tcp: implement the get_opt() function
It relies on the generic sock_conn_get_opt() function and will permit
sample fetch functions to retrieve generic TCP-level info.
2025-12-24 18:38:51 +01:00
Willy Tarreau
6d995e59e9 MINOR: protocol: support a generic way to call getsockopt() on a connection
It's regularly needed to call getsockopt() on a connection, but each
time the calling code has to do all the job by itself. This commit adds
a "get_opt()" callback on the protocol struct, that directly calls
getsockopt() on the connection's FD. A generic implementation for
standard sockets is provided, though QUIC would likely require a
different approach, or maybe a mapping. Due to the overlap between
IP/TCP/socket option values, it is necessary for the caller to indicate
both the level and the option. An abstraction of the level could be
done, but the caller would nonetheless have to know the optname, which
is generally defined in the same include files. So for now we'll
consider that this callback is only for very specific use.

The levels and optnames are purposely passed as signed ints so that it
is possible to further extend the API by using negative levels for
internal namespaces.
2025-12-24 18:38:51 +01:00
Willy Tarreau
44c67a08dd MINOR: tcp: add new bind option "tcp-ss" to instruct the kernel to save the SYN
This option enables TCP_SAVE_SYN on the listening socket, which will
cause the kernel to try to save a copy of the SYN packet header (L2,
IP and TCP are supported). This can permit to check the source MAC
address of a client, or find certain TCP options such as a source
address encapsulated using RFC7974. It could also be used as an
alternate approach to retrieving the source and destination addresses
and ports. For now setting the option is enabled, but sample fetch
functions and converters will be needed to extract info.
2025-12-24 11:35:09 +01:00
Maxime Henrion
1fdccbe8da OPTIM: patterns: cache the current generation
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
This makes a significant difference when loading large files and during
commit and clear operations, thanks to improved cache locality. In the
measurements below, master refers to the code before any of the changes
to the patterns code, not the code before this one commit.

Timing the replacement of 10M entries from the CLI with this command
which also reports timestamps at start, end of upload and end of clear:

  $ (echo "prompt i"; echo "show activity"; echo "prepare acl #0";
     awk '{print "add acl @1 #0",$0}' < bad-ip.map; echo "show activity";
     echo "commit acl @1 #0"; echo "clear acl @0 #0";echo "show activity") |
    socat -t 10 - /tmp/sock1 | grep ^uptim

master, on a 3.7 GHz EPYC, 3 samples:

  uptime_now: 6.087030
  uptime_now: 25.981777  => 21.9 sec insertion time
  uptime_now: 29.286368  => 3.3 sec commit+clear

  uptime_now: 5.748087
  uptime_now: 25.740675  => 20.0s insertion time
  uptime_now: 29.039023  => 3.3 s commit+clear

  uptime_now: 7.065362
  uptime_now: 26.769596  => 19.7s insertion time
  uptime_now: 30.065044  => 3.3s commit+clear

And after this commit:

  uptime_now: 6.119215
  uptime_now: 25.023019  => 18.9 sec insertion time
  uptime_now: 27.155503  => 2.1 sec commit+clear

  uptime_now: 5.675931
  uptime_now: 24.551035  => 18.9s insertion
  uptime_now: 26.652352  => 2.1s commit+clear

  uptime_now: 6.722256
  uptime_now: 25.593952  => 18.9s insertion
  uptime_now: 27.724153  => 2.1s commit+clear

Now timing the startup time with a 10M entries file (on another machine)
on master, 20 samples:

Standard Deviation, s: 0.061652677408033
Mean:        4.217

And after this commit:

Standard Deviation, s: 0.081821371548669
Mean:        3.78
2025-12-23 21:17:39 +01:00
Maxime Henrion
99e625a41d CLEANUP: patterns: remove dead code
Situations where we are iterating over elements and find one with a
different generation ID cannot arise anymore since the elements are kept
per-generation.
2025-12-23 21:17:39 +01:00
Maxime Henrion
545cf59b6f MEDIUM: patterns: reorganize pattern reference elements
Instead of a global list (and tree) of pattern reference elements, we
now have an intermediate pat_ref_gen structure and store the elements in
those. This simplifies the logic of some operations such as commit and
clear, and improves performance in some cases - numbers to be provided
in a subsequent commit after one important optimization is added.

A lot of the changes are due to adding an extra level of indirection,
changing many cases where we iterate over all elements to an outer loop
iterating over the generation and an inner one iterating over the
elements of the current generation. It is therefore easier to read this
patch using 'git diff -w'.
2025-12-23 21:17:39 +01:00
Maxime Henrion
5547bedebb MINOR: patterns: preliminary changes for reorganization
Safe and non-functional changes that only add currently unused
structures, field, functions and macros, in preparation of larger
changes that alter the way pattern reference elements are stored.

This includes code to create and lookup generation objects, and
macros to iterate over the generations of a pattern reference.
2025-12-23 21:17:39 +01:00
Amaury Denoyelle
a4a17eb366 OPTIM/MINOR: proxy: do not init proxy management task if unused
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
Each proxy has its owned task for internal purpose. Currently, it is
only used either by frontends or if a stick-table is present.

This commit rendres the task allocation optional to only the required
case. Thus, it is not allocated anymore for backend only proxies without
stick-table.
2025-12-23 16:35:49 +01:00
Amaury Denoyelle
c397f6fc9a MINOR: cfgparse: remove useless checks on no server in backend
A legacy check could be activated at compile time to reject backends
without servers. In practice this is not used anymore and does not have
much sense with the introduction of dynamic servers.
2025-12-23 16:35:49 +01:00
Amaury Denoyelle
b562602044 MEDIUM: cfgparse: acknowledge that proxy ID auto numbering starts at 2
Each frontend/backend/listen proxies is assigned an unique ID. It can
either be set explicitely via 'id' keyword, or automatically assigned on
post parsing depending on the available values.

It was expected that the first automatically assigned value would start
at '1'. However, due to a legacy bug this is not the case as this value
is always skipped. Thus, automatically assigned proxies always start at
'2' or more.

To avoid breaking the current existing state, this situation is now
acknowledged with the current patch. The code is rewritten with an
explicit warning to ensure that this won't be fixed without knowing the
current status. A new regtest also ensures this.
2025-12-23 16:35:49 +01:00
Willy Tarreau
5904f8279b MINOR: mux-h1: perform a graceful close at 75% glitches threshold
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
This avoids hitting the hard wall for connections with non-compliant
peers that are accumulating errors. We recycle the connection early
enough to permit to reset the counter. Example below with a threshold
set to 100:

Before, 1% errors:
  $ h1load -H "Host : blah" -c 1 -n 10000000 0:4445
  #     time conns tot_conn  tot_req      tot_bytes    err  cps  rps  bps   ttfb
           1     1     1039   103872        6763365   1038 1k03 103k 54M1 9.426u
           2     1     2128   212793       14086140   2127 1k08 108k 58M5 8.963u
           3     1     3215   321465       21392137   3214 1k08 108k 58M3 8.982u
           4     1     4307   430684       28735013   4306 1k09 109k 58M6 8.935u
           5     1     5390   538989       36016294   5389 1k08 108k 58M1 9.021u

After, no more errors:
  $ h1load -H "Host : blah" -c 1 -n 10000000 0:4445
  #     time conns tot_conn  tot_req      tot_bytes    err  cps  rps  bps   ttfb
           1     1     1509   113161        7487809      0 1k50 113k 59M9 8.482u
           2     1     3002   225101       15114659      0 1k49 111k 60M9 8.582u
           3     1     4508   338045       22809911      0 1k50 112k 61M5 8.523u
           4     1     5971   447785       30286861      0 1k46 109k 59M7 8.772u
           5     1     7472   560335       37955271      0 1k49 112k 61M2 8.537u
2025-12-20 19:29:37 +01:00
Willy Tarreau
05b457002b MEDIUM: mux-h1: implement basic glitches support
We now count glitches for each parsing error, including those that
have been accepted via accept-unsafe-violations-*. Front and back
are considered and the connection gets killed on error once if the
threshold is reached or passed and the CPU usage is beyond the
configured limit (0 by default). This was tested with:

   curl -ivH "host : blah" 0:4445{,,,,,,,,,}

which sends 10 requests to a configuration having a threshold of 5.
The global keywords are named similarly to H2 and quic:

     tune.h1.be.glitches-threshold xxxx
     tune.h1.fe.glitches-threshold xxxx

The glitches count of each connection is also reported when non-null
in the connection dumps (e.g. "show fd").
2025-12-20 19:29:33 +01:00
Willy Tarreau
0901f60cef MINOR: mux-h2: perform a graceful close at 75% glitches threshold
This avoids hitting the hard wall for connections with non-compliant
peers that would be accumulating errors over long connections. We now
permit to recycle the connection early enough to reset the connection
counter.

This was tested artificially by adding this to h2c_frt_handle_headers():

  h2c_report_glitch(h2c, 1, "new stream");

or this to h2_detach():

  h2c_report_glitch(h2c, 1, "detaching");

and injecting using h2load -c 1 -n 1000 0:4445 on a config featuring
tune.h2.fe.glitches-threshold 1000:

  finished in 8.74ms, 85802.54 req/s, 686.62MB/s
  requests: 1000 total, 751 started, 751 done, 750 succeeded, 250 failed, 250 errored, 0 timeout
  status codes: 750 2xx, 0 3xx, 0 4xx, 0 5xx
  traffic: 6.00MB (6293303) total, 132.57KB (135750) headers (space savings 29.84%), 5.86MB (6144000) data
                       min         max         mean         sd        +/- sd
  time for request:        9us       178us        10us         6us    99.47%
  time for connect:      139us       139us       139us         0us   100.00%
  time to 1st byte:      339us       339us       339us         0us   100.00%
  req/s           :   87477.70    87477.70    87477.70        0.00   100.00%

The failures are due to h2load not supporting reconnection.
2025-12-20 19:26:29 +01:00
Willy Tarreau
52adeef7e1 MINOR: mux-h2: add missing glitch count for non-decodable H2 headers
One rare error case could produce a protocol error on the stream when
not being able to decode response headers wasn't being accounted as a
glitch, so let's fix it.
2025-12-20 19:11:16 +01:00
Maxime Henrion
c8750e4e9d MINOR: tools: add a secure implementation of memset
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
This guarantees that the compiler will not optimize away the memset()
call if it detects a dead store.

Use this to clear SSL passphrases.

No backport needed.
2025-12-19 17:42:57 +01:00
William Lallemand
03340748de BUG/MINOR: cpu-topo: fix -Wlogical-not-parentheses build with clang
src/cpu_topo.c:1325:15: warning: logical not is only applied to the left hand side of this bitwise operator [-Wlogical-not-parentheses]
 1325 |                         } else if (!cpu_policy_conf.flags & CPU_POLICY_ONE_THREAD_PER_CORE)
      |                                    ^                      ~
src/cpu_topo.c:1325:15: note: add parentheses after the '!' to evaluate the bitwise operator first
 1325 |                         } else if (!cpu_policy_conf.flags & CPU_POLICY_ONE_THREAD_PER_CORE)
      |                                    ^
      |                                     (                                                     )
src/cpu_topo.c:1325:15: note: add parentheses around left hand side expression to silence this warning
 1325 |                         } else if (!cpu_policy_conf.flags & CPU_POLICY_ONE_THREAD_PER_CORE)
      |                                    ^
      |                                    (                     )
src/cpu_topo.c:1533:15: warning: logical not is only applied to the left hand side of this bitwise operator [-Wlogical-not-parentheses]
 1533 |                         } else if (!cpu_policy_conf.flags & CPU_POLICY_ONE_THREAD_PER_CORE)
      |                                    ^                      ~
src/cpu_topo.c:1533:15: note: add parentheses after the '!' to evaluate the bitwise operator first
 1533 |                         } else if (!cpu_policy_conf.flags & CPU_POLICY_ONE_THREAD_PER_CORE)
      |                                    ^
      |                                     (                                                     )
src/cpu_topo.c:1533:15: note: add parentheses around left hand side expression to silence this warning
 1533 |                         } else if (!cpu_policy_conf.flags & CPU_POLICY_ONE_THREAD_PER_CORE)
      |                                    ^
      |                                    (                     )

No backport needed.
2025-12-19 10:15:17 +01:00
Olivier Houchard
8aef5bec1e MEDIUM: cpu-topo: Add the "per-ccx" cpu_affinity
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
Add a new cpu-affinity keyword, "per-ccx".
If used, each thread will be bound to all the hardware threads available
in one CCX of the threads group.
2025-12-18 18:52:52 +01:00
Olivier Houchard
c524b181a2 MEDIUM: cpu-topo: Add the "per-thread" cpu_affinity
Add a new cpu-affinity keyword, "per-thread".
If used, each thread will be bound to only one hardware thread of the
thread group.
If used in conjonction with the "threads-per-core 1" cpu_policy, then
each thread will be bound on a different core.
2025-12-18 18:52:52 +01:00
Olivier Houchard
7e22d9c484 MEDIUM: cpu-topo: Add a new "max-threads-per-group" global keyword
Add a new global keyword, max-threads-per-group. It sets the maximum number of
threads a thread group can contain. Unless the number of thread groups
is fixed with "thread-groups", haproxy will just create more thread
groups as needed.
The default and maximum value is 64.
2025-12-18 18:52:52 +01:00
Olivier Houchard
3865f6c5c6 MEDIUM: cpu-topo: Add a "cpu-affinity" option
Add a new global option, "cpu-affinity", which controls how threads are
bound.
It currently accepts three values, "per-core", which will bind one thread to
each hardware thread of a given core, and "per-group" which will use all
the available hardware threads of the thread group, and "auto", the
default, which will use "per-group", unless "threads-per-core 1" has
been specified in cpu_policy, in which case it will use per-core.
2025-12-18 18:52:52 +01:00
Olivier Houchard
3671652bc9 MEDIUM: cpu-topo: Add a "threads-per-core" keyword to cpu-policy
Add a new, optional key-word to "cpu-policy", "threads-per-core".
It takes one argument, "1" or "auto". If "1" is used, then only one
thread per core will be created, no matter how many hardware thread each
core has. If "auto" is used, then one thread will be created per
hardware thread, as is the case by default.

for example: cpu-policy performance threads-per-core 1
2025-12-18 18:52:52 +01:00
Olivier Houchard
58f04b4615 MINOR: cpu-topo: Turn the cpu policy configuration into a struct
Turn the cpu policy configuration into a struct. Right now it just
contains an int, that represents the policy used, but will get more
information soon.
2025-12-18 18:52:52 +01:00
Willy Tarreau
9a046fc3ad BUG/MEDIUM: mux-h2: synchronize all conditions to create a new backend stream
In H2 the conditions to create a new stream differ for a client and a
server when a GOAWAY was exchanged. While on the server, any stream
whose ID is lower than or equal to the one advertised in GOAWAY is
valid, for a client it's forbidden to create any stream after receipt
of a GOAWAY, even if its ID is lower than or equal to the last one,
despite the server not being able to tell the difference from the
number of streams in flight.

Unfortunately, the logic in the code did not always reflect this
specificity of the client (the backend code in our case), and most
often considered that it was still permitted to create a new stream
until the max_id was greater than or equal to the advertised last_id.
This is for example what h2c_is_dead() and h2c_streams_left() do. In
other places, such as h2_avail_streams(), the rule is properly taken
into account. Very often the advertised last_id is the same, and this
is also what haproxy does (which explains why it's impossible to
reproduce the issue by chaining two haproxy layers), but a server may
wish to advertise any ID including 2^31-1 as mentioned in the spec,
and in this case the functions would behave differently.

This discrepancy results in a corner case where a GOAWAY received on
an idle connection will cause the next stream creation to be initially
accepted but then rejected via h2_avail_streams(), and the connection
left in a bad state, still attached to the session due to http-reuse
safe, but not reinserted into idle list, since the backend code
currently is not able to properly recover from this situation. Worse,
the idle flags are no longer on it but TASK_F_USR1 still is, and this
makes the recently added BUG_ON() rightfully trigger since this case
is not supposed to happen.

Admittedly more of the backend recovery code needs to be reworked,
however the mux must consistently decide whether or not a connection
may be reused or needs to be released.

This commit fixes the affected logic by introducing a new function
"h2c_reached_last_stream()" which says if a connection has reached its
last stream, regardless of the side, and using this one everywhere
max_id was compared to last_id. This is sufficient to address the
corner case that be_reuse_connection() currently cannot recover from.

This is in relation to GH issue #3215 and it should be sufficient to
fix the issue there. Thanks to Chris Staite for reporting the issue
and kudos to Amaury for spotting the events sequence that can lead
to this situation.

This patch must be backported to 3.3 first, then to older versions
later. It's worth noting that it's much more difficult to observe
the issue before 3.3 because the BUG_ON() is not there, and the
possibly non-released connection might end up being killed for other
reasons (timeouts etc). But one possible visible effect might be the
impossibility to delete a server (which Chris observed in 3.3).
2025-12-18 17:01:32 +01:00
Olivier Houchard
40d16af7a6 BUG/MEDIUM: backend: Do not remove CO_FL_SESS_IDLE in assign_server()
Back in the mists of time, commit e91a526c8f decided that if we were trying
to stay on the same server than the previous request, and if there were
a connection available in the session, we'd remove its CO_FL_SESS_IDLE.
The reason for doing that has been long lost, probably it fixed a bug at some
point, but it was most probably not the right place to do that. And starting
with 3.3, this triggers a BUG_ON() because that flag is expected later on.
So just revert the commit, if the ancient bug shows up again, it will be
fixed another way.

This should be backported to 3.3. There is little reason to backport it
to previous versions, unless other patches depend on it.
2025-12-18 16:09:34 +01:00
Christopher Faulet
a25394b6c8 CLEANUP: ssl-sock: Remove useless tests on connection when resuming TLS session
In ssl_sock_srv_try_reuse_sess(), the connection is always defined, to TCP
and QUIC connections. No reason to test it. Because it is not so obvious for
the QUIC part, a BUG_ON() could be added here. For now, just remove useless
tests.

This patch should fix a Coverity report from #3213.
2025-12-15 08:16:59 +01:00
Christopher Faulet
d6b1d5f6e9 CLEANUP: tcpcheck: Remove useless test on the xprt used for healthchecks
The xprt used to perform a healthcheck is always defined and cannot be NULL.
So there is no reason to test it. It could lead to wrong assumptions later
in the code.

This patch should fix a Coverity report from #3213.
2025-12-15 08:01:21 +01:00
Christopher Faulet
5c5914c32e CLEANUP: backend: Remove useless test on server's xprt
The server's xprt is always defined and cannot be NULL. So there is no
reason to test it. It could lead to wrong assumptions later in the code.

This patch should fix a Coverity report from #3213.
2025-12-15 07:56:53 +01:00
Olivier Houchard
a08bc468d2 BUG/MEDIUM: quic: Don't try to use hystart if not implemented
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
Not every CC algos implement hystart, so only call the method if it is
actually there. Failure to do so will cause crashes if hystart is on,
and the algo doesn't implement it.

This should fix github issue #3218

This should be backported up to 3.0.
2025-12-14 16:46:12 +01:00
Christopher Faulet
54e58103e5 BUG/MEDIUM: stconn: Don't report abort from SC if read0 was already received
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
SC_FL_ABRT_DONE flag should never be set when SC_FL_EOS was already
set. These both flags were introduced to replace the old CF_SHUTR and to
have a flag for shuts driven by the stream and a flag for the read0 received
by the mux. So both flags must not be seen at same time on a SC. It is
espeically important because some processing are performed when these flags
are set. And wrong decisions may be made.

This patch must be backproted as far as 2.8.
2025-12-12 08:41:08 +01:00
Christopher Faulet
a483450fa2 BUG/MEDIUM: http-ana: Properly detect client abort when forwarding response (v2)
The first attempt to fix this issue (c672b2a29 "BUG/MINOR: http-ana:
Properly detect client abort when forwarding the response") was not fully
correct and could be responsible to false report of client abort during the
response forwarding. I guess it is possible to truncate the response.

Instead, we must also take care that the client closed on its side, by
checking SC_FL_EOS flag on the front SC. Indeed, if the client has aborted,
this flag should be set.

This patch should be backported as far as 2.8.
2025-12-12 08:41:08 +01:00
William Lallemand
5b19d95850 BUG/MEDIUM: mworker/listener: ambiguous use of RX_F_INHERITED with shards
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
The RX_F_INHERITED flag was ambiguous, as it was used to mark both
listeners inherited from the parent process and listeners duplicated
from another local receiver. This could lead to incorrect behavior
concerning socket unbinding and suspension.

This commit refactors the handling of inherited listeners by splitting
the RX_F_INHERITED flag into two more specific flags:

- RX_F_INHERITED_FD: Indicates a listener inherited from the parent
  process via its file descriptor. These listeners should not be unbound
  by the master.

- RX_F_INHERITED_SOCK: Indicates a listener that shares a socket with
  another one, either by being inherited from the parent or by being
  duplicated from another local listener. These listeners should not be
  suspended or resumed individually.

Previously, the sharding code was unconditionally using RX_F_INHERITED
when duplicating a file descriptor. In HAProxy versions prior to 3.1,
this led to a file descriptor leak for duplicated unix stats sockets in
the master process. This would eventually cause the master to crash with
a BUG_ON in fd_insert() once the file descriptor limit was reached.

This must be backported as far as 3.0. Branches earlier than 3.0 are
affected but would need a different patch as the logic is different.
2025-12-11 18:09:47 +01:00
Willy Tarreau
3ec5818807 MINOR: h2/trace: emit a trace of the received RST_STREAM type
Right now we don't get any state trace when receiving an RST_STREAM, and
this is not convenient because RST_STREAM(0) is not visible at all, except
in developer level because the function is entered and left.

Let's extract the RST code first and always log it using TRACE_PRINTF()
(along with h2c/h2s) so that it's possible to detect certain codes being
used.
2025-12-10 15:58:56 +01:00
Amaury Denoyelle
5b8e6d6811 BUG/MEDIUM: h3: fix access to QCS <sd> definitely
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
The previous patch tried to fix access to QCS <sd> member, as the latter
is not always allocated anymore on the frontend side.

  a15f0461a0
  BUG/MEDIUM: h3: do not access QCS <sd> if not allocated

In particular, access was prevented after HEADERS parsing in case
h3_req_headers_to_htx() returned an error, which indicates that the
stream-endpoint allocation was not performed. However, this still is not
enough when QCS instance is already closed at this step. Indeed, in this
case, h3_req_headers_to_htx() returns OK but stream-endpoint allocation
is skipped as an optimization as no data exchange will be performed.

To definitely fix this kind of problems, add checks on qcs <sd> member
before accessing it in H3 layer. This method is the safest one to ensure
there is no NULL dereferencement.

This should fix github issue #3211.

This must be backported along the above mentionned patch.
2025-12-10 12:04:37 +01:00
Maxime Henrion
6eedd0d485 CLEANUP: more conversions and cleanups for alignment
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
- Convert additional cases to use the automatic alignment feature for
  the THREAD_ALIGN(ED) macros. This includes some cases that are less
  obviously correct where it seems we wanted to align only in the
  USE_THREAD case but were not using the thread specific macros.
- Also move some alignment requirements to the structure definition
  instead of having it on variable declaration.
2025-12-09 17:40:58 +01:00
Maxime Henrion
bc8e14ec23 CLEANUP: use the automatic alignment feature
- Use the automatic alignment feature instead of hardcoding 64 all over
  the code.
- This also converts a few bare __attribute__((aligned(X))) to using the
  ALIGNED macro.
2025-12-09 17:14:58 +01:00
Olivier Houchard
420b42df1c BUG/MEDIUM: ssl: Don't resume session for check connections
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
Don't attempt to use stored sessions when creating new check
connections, as the check SSL parameters might be different from the
server's ones.
This has not been proven to be a problem yet, but it doesn't mean it
can't be, and this should be backported up to 2.8 along with
dcce936912 if it is.
2025-12-09 16:45:54 +01:00
Olivier Houchard
be4e1220c2 BUG/MEDIUM: ssl: Don't store the ALPN for check connections
When establishing check connections, do not store the negociated ALPN
into the server's path_param if the connection is a check connection, as
it may use different SSL parameters than the regular connections. To do
so, only store them if the CO_FL_SSL_NO_CACHED_INFO is not set.
Otherwise, the check ALPN may be stored, and the wrong mux can be used
for regular connections, which will end up generating 502s.

This should fix Github issue #3207

This should be backported to 3.3.
2025-12-09 16:43:31 +01:00
Olivier Houchard
dcce936912 MINOR: connections: Add a new CO_FL_SSL_NO_CACHED_INFO flag
Add a new flag to connections, CO_FL_SSL_NO_CACHED_INFO, and set it for
checks.
It lets the ssl layer know that he should not use cached informations,
such as the ALPN as stored in the server, or cached sessions.
This wlil be used for checks, as checks may target different servers, or
used a different SSL configuration, so we can't assume the stored
informations are correct.

This should be backported to 3.3, and may be backported up to 2.8 if the
attempts to do session resume by checks is proven to be a problem.
2025-12-09 16:43:31 +01:00
Olivier Houchard
260d64d787 BUG/MEDIUM: ssl: Always check the ALPN after handshake
Move the code that is responsible for checking the ALPN, and updating
the one stored in the server's path_param, from after we created the
mux, to after we did an handshake. Once we did it once, the mux will not
be created by the ssl code anymore, as when we know which mux to use
thanks to the ALPN, it will be done earlier in connect_server(), so in
the unlikely event it changes, we would not detect it anymore, and we'd
keep on creating the wrong mux.
This can be reproduced by doing a first request, and then changing the
ALPN of the server without haproxy noticing (ie without haproxy noticing
that the server went down).

This should be backported to 3.3.
2025-12-09 16:43:31 +01:00