Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package haproxy for openSUSE:Factory checked in at 2026-02-12 17:30:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/haproxy (Old) and /work/SRC/openSUSE:Factory/.haproxy.new.1977 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "haproxy" Thu Feb 12 17:30:48 2026 rev:176 rq:1332730 version:3.3.3+git0.465d8e2fc Changes: -------- --- /work/SRC/openSUSE:Factory/haproxy/haproxy.changes 2026-02-06 19:18:01.791520873 +0100 +++ /work/SRC/openSUSE:Factory/.haproxy.new.1977/haproxy.changes 2026-02-12 17:30:57.244416434 +0100 @@ -1,0 +2,25 @@ +Thu Feb 12 15:16:46 UTC 2026 - Marcus Rueckert <[email protected]> + +- Update to version 3.3.3+git0.465d8e2fc: + (boo#1257976 CVE-2026-26081 CVE-2026-26080) + * [RELEASE] Released version 3.3.3 + * BUG/MAJOR: quic: fix parsing frame type + * BUG/MAJOR: quic: reject invalid token + * BUG/MINOR: backend: fix access on shared counters array + * BUG/MINOR: quic: ensure handshake speed up is only run once per conn + * BUG/MINOR: ssl: SSL_CERT_DIR environment variable doesn't affect haproxy + * MINOR: activity: allow to switch per-task lock/memory profiling at runtime + * MEDIUM: activity: apply and use new finegrained task profiling settings + * MINOR: activity: support setting/clearing lock/memory watching for task profiling + * BUG/MINOR: startup: handle a possible strdup() failure + * BUG/MINOR: startup: fix allocation error message of progname string + * BUG/MINOR: config: Fix setting of alt_proto + * MEDIUM: backend: make "balance random" consider req rate when loads are equal + * DOC: config: mention the limitation on server id range for consistent hash + * BUG/MEDIUM: lb-chash: always properly initialize lb_nodes with dynamic servers + * CLEANUP: lb-chash: free lb_nodes from chash's deinit(), not global + * BUG/MINOR: cpu-topo: count cores not cpus to distinguish core types + * CLEANUP: haproxy: fix bad line wrapping in run_poll_loop() + * BUG/MEDIUM: threads: Atomically set TH_FL_SLEEPING and clr FL_NOTIFIED + +------------------------------------------------------------------- Old: ---- haproxy-3.3.2+git3.bc0fb5969.tar.gz New: ---- haproxy-3.3.3+git0.465d8e2fc.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ haproxy.spec ++++++ --- /var/tmp/diff_new_pack.w07BoB/_old 2026-02-12 17:30:58.276460227 +0100 +++ /var/tmp/diff_new_pack.w07BoB/_new 2026-02-12 17:30:58.280460397 +0100 @@ -49,7 +49,7 @@ %bcond_with ech Name: haproxy -Version: 3.3.2+git3.bc0fb5969 +Version: 3.3.3+git0.465d8e2fc Release: 0 # Summary: The Reliable, High Performance TCP/HTTP Load Balancer ++++++ _service ++++++ --- /var/tmp/diff_new_pack.w07BoB/_old 2026-02-12 17:30:58.388464980 +0100 +++ /var/tmp/diff_new_pack.w07BoB/_new 2026-02-12 17:30:58.392465150 +0100 @@ -6,10 +6,7 @@ <param name="versionformat">@PARENT_TAG@+git@TAG_OFFSET@.%h</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="versionrewrite-replacement">\1</param> - <!-- - <param name="revision">v3.3.2</param> - --> - <param name="revision">master</param> + <param name="revision">v3.3.3</param> <param name="changesgenerate">enable</param> </service> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.w07BoB/_old 2026-02-12 17:30:58.424466508 +0100 +++ /var/tmp/diff_new_pack.w07BoB/_new 2026-02-12 17:30:58.440467187 +0100 @@ -5,7 +5,7 @@ </service> <service name="tar_scm"> <param name="url">http://git.haproxy.org/git/haproxy-3.3.git/</param> - <param name="changesrevision">bc0fb5969e500ea5702bf885dd1fea110f6b3ce6</param> + <param name="changesrevision">465d8e2fcfcbf4bbcf36c3f53a801369f4e7e922</param> </service> </servicedata> (No newline at EOF) ++++++ haproxy-3.3.2+git3.bc0fb5969.tar.gz -> haproxy-3.3.3+git0.465d8e2fc.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/CHANGELOG new/haproxy-3.3.3+git0.465d8e2fc/CHANGELOG --- old/haproxy-3.3.2+git3.bc0fb5969/CHANGELOG 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/CHANGELOG 2026-02-12 14:25:57.000000000 +0100 @@ -1,6 +1,29 @@ ChangeLog : =========== +2026/02/12 : 3.3.3 + - MEDIUM: h1: strictly verify quoting in chunk extensions + - DOC: internals: cleanup few typos in master-worker documentation + - BUG/MEDIUM: applet: Fix test on shut flags for legacy applets + - BUG/MEDIUM: threads: Atomically set TH_FL_SLEEPING and clr FL_NOTIFIED + - CLEANUP: haproxy: fix bad line wrapping in run_poll_loop() + - BUG/MINOR: cpu-topo: count cores not cpus to distinguish core types + - CLEANUP: lb-chash: free lb_nodes from chash's deinit(), not global + - BUG/MEDIUM: lb-chash: always properly initialize lb_nodes with dynamic servers + - DOC: config: mention the limitation on server id range for consistent hash + - MEDIUM: backend: make "balance random" consider req rate when loads are equal + - BUG/MINOR: config: Fix setting of alt_proto + - BUG/MINOR: startup: fix allocation error message of progname string + - BUG/MINOR: startup: handle a possible strdup() failure + - MINOR: activity: support setting/clearing lock/memory watching for task profiling + - MEDIUM: activity: apply and use new finegrained task profiling settings + - MINOR: activity: allow to switch per-task lock/memory profiling at runtime + - BUG/MINOR: ssl: SSL_CERT_DIR environment variable doesn't affect haproxy + - BUG/MINOR: quic: ensure handshake speed up is only run once per conn + - BUG/MINOR: backend: fix access on shared counters array + - BUG/MAJOR: quic: reject invalid token + - BUG/MAJOR: quic: fix parsing frame type + 2026/01/29 : 3.3.2 - MINOR: mux-h2: add missing glitch count for non-decodable H2 headers - MINOR: mux-h2: perform a graceful close at 75% glitches threshold diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/VERDATE new/haproxy-3.3.3+git0.465d8e2fc/VERDATE --- old/haproxy-3.3.2+git3.bc0fb5969/VERDATE 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/VERDATE 2026-02-12 14:25:57.000000000 +0100 @@ -1,2 +1,2 @@ $Format:%ci$ -2026/01/29 +2026/02/12 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/VERSION new/haproxy-3.3.3+git0.465d8e2fc/VERSION --- old/haproxy-3.3.2+git3.bc0fb5969/VERSION 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/VERSION 2026-02-12 14:25:57.000000000 +0100 @@ -1 +1 @@ -3.3.2 +3.3.3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/doc/configuration.txt new/haproxy-3.3.3+git0.465d8e2fc/doc/configuration.txt --- old/haproxy-3.3.2+git3.bc0fb5969/doc/configuration.txt 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/doc/configuration.txt 2026-02-12 14:25:57.000000000 +0100 @@ -3,7 +3,7 @@ Configuration Manual ---------------------- version 3.3 - 2026/01/29 + 2026/02/12 This document covers the configuration language as implemented in the version @@ -3962,7 +3962,7 @@ use in production. The same may be achieved at run time on the CLI using the "set profiling memory" command, please consult the management manual. -profiling.tasks { auto | on | off } +profiling.tasks { auto | on | off | lock | no-lock | memory | no-memory }* Enables ('on') or disables ('off') per-task CPU profiling. When set to 'auto' the profiling automatically turns on a thread when it starts to suffer from an average latency of 1000 microseconds or higher as reported in the @@ -3973,6 +3973,18 @@ systems, containers, or virtual machines, or when the system swaps (which must absolutely never happen on a load balancer). + When task profiling is enabled, HAProxy can also collect the time each task + spends with a lock held or waiting for a lock, as well as the time spent + waiting for a memory allocation to succeed in case of a pool cache miss. This + can sometimes help understand certain causes of latency. For this, the extra + keywords "lock" (to enable lock time collection), "no-lock" (to disable it), + "memory" (to enable memory allocation time collection) or "no-memory" (to + disable it) may additionally be passed. By default they are not enabled since + they can have a non-negligible CPU impact on highly loaded systems (3-10%). + Note that the overhead is only taken when profiling is effectively running, + so that when running in "auto" mode, it will only appear when HAProxy decides + to turn it on. + CPU profiling per task can be very convenient to report where the time is spent and which requests have what effect on which other request. Enabling it will typically affect the overall's performance by less than 1%, thus it @@ -6182,8 +6194,16 @@ will take away N-1 of the highest loaded servers at the expense of performance. With very high values, the algorithm will converge towards the leastconn's result but much slower. + In addition, for large server farms with very low loads (or + perfect balance), comparing loads will often lead to a tie, + so in case of equal loads between all measured servers, their + request rate over the last second are compared, which allows + to better balance server usage over time in the same spirit + as roundrobin does, and smooth consistent hash unfairness. The default value is 2, which generally shows very good - distribution and performance. This algorithm is also known as + distribution and performance. For large farms with low loads + (less than a few requests per second per server), it may help + to raise it to 3 or even 4. This algorithm is also known as the Power of Two Random Choices and is described here : http://www.eecs.harvard.edu/~michaelm/postscripts/handbook2001.pdf @@ -18190,7 +18210,10 @@ id The node keys will be derived from the server's numeric identifier as set from "id" or which defaults to its position - in the server list. + in the server list. This is the default. Note that only the 28 + lowest bits of the ID will be used (i.e. (id % 268435456)), so + better only use values comprised between 1 and this value to + avoid overlap. addr The node keys will be derived from the server's address, when available, or else fall back on "id". @@ -18202,7 +18225,9 @@ HAProxy processes are balancing traffic to the same set of servers. If the server order of each process is different (because, for example, DNS records were resolved in different orders) then this will allow each independent - HAProxy processes to agree on routing decisions. + HAProxy processes to agree on routing decisions. Note: "balance random" also + uses "hash-type consistent", and the quality of the distribution will depend + on the quality of the keys. id <value> May be used in the following contexts: tcp, http, log diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/doc/management.txt new/haproxy-3.3.3+git0.465d8e2fc/doc/management.txt --- old/haproxy-3.3.2+git3.bc0fb5969/doc/management.txt 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/doc/management.txt 2026-02-12 14:25:57.000000000 +0100 @@ -2529,7 +2529,8 @@ delayed until the threshold is reached. A value of zero restores the initial setting. -set profiling { tasks | memory } { auto | on | off } +set profiling memory { on | off } +set profiling tasks { auto | on | off | lock | no-lock | memory | no-memory } Enables or disables CPU or memory profiling for the indicated subsystem. This is equivalent to setting or clearing the "profiling" settings in the "global" section of the configuration file. Please also see "show profiling". Note @@ -2539,6 +2540,13 @@ on the linux-glibc target), and requires USE_MEMORY_PROFILING to be set at compile time. +. For tasks profiling, it is possible to enable or disable the collection of + per-task lock and memory timings at runtime, but the change is only taken + into account next time the profiler switches from off/auto to on (either + automatically or manually). Thus when using "no-lock" to disable per-task + lock profiling and save CPU cycles, it is recommended to flip the task + profiling off then on to commit the change. + set rate-limit connections global <value> Change the process-wide connection rate limit, which is set by the global 'maxconnrate' setting. A value of zero disables the limitation. This limit diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/activity-t.h new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/activity-t.h --- old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/activity-t.h 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/activity-t.h 2026-02-12 14:25:57.000000000 +0100 @@ -33,6 +33,8 @@ #define HA_PROF_TASKS_MASK 0x00000003 /* per-task CPU profiling mask */ #define HA_PROF_MEMORY 0x00000004 /* memory profiling */ +#define HA_PROF_TASKS_MEM 0x00000008 /* per-task CPU profiling with memory */ +#define HA_PROF_TASKS_LOCK 0x00000010 /* per-task CPU profiling with locks */ #ifdef USE_MEMORY_PROFILING diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/backend-t.h new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/backend-t.h --- old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/backend-t.h 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/backend-t.h 2026-02-12 14:25:57.000000000 +0100 @@ -192,6 +192,7 @@ void (*server_requeue)(struct server *); /* function used to place the server where it must be */ void (*proxy_deinit)(struct proxy *); /* to be called when we're destroying the proxy */ void (*server_deinit)(struct server *); /* to be called when we're destroying the server */ + int (*server_init)(struct server *); /* initialize a freshly added server (runtime); <0=fail. */ }; #endif /* _HAPROXY_BACKEND_T_H */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/ssl_ckch.h new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/ssl_ckch.h --- old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/ssl_ckch.h 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/ssl_ckch.h 2026-02-12 14:25:57.000000000 +0100 @@ -80,6 +80,7 @@ int ssl_store_load_ca_from_buf(struct cafile_entry *ca_e, char *cert_buf, int append); int ssl_store_load_locations_file(char *path, int create_if_none, enum cafile_type type); int __ssl_store_load_locations_file(char *path, int create_if_none, enum cafile_type type, int shuterror); +const char *ha_default_cert_dir(); extern struct cert_exts cert_exts[]; extern int (*ssl_commit_crlfile_cb)(const char *path, X509_STORE *ctx, char **err); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/thread.h new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/thread.h --- old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/thread.h 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/thread.h 2026-02-12 14:25:57.000000000 +0100 @@ -364,15 +364,19 @@ extern uint64_t now_mono_time(void); \ if (_LK_ != _LK_UN) { \ th_ctx->lock_level += bal; \ - if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) \ + if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \ + (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) \ lock_start = now_mono_time(); \ } \ (void)(expr); \ if (_LK_ == _LK_UN) { \ th_ctx->lock_level += bal; \ - if (th_ctx->lock_level == 0 && unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) \ + if (th_ctx->lock_level == 0 &&\ + unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \ + (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) \ th_ctx->locked_total += now_mono_time() - th_ctx->lock_start_date; \ - } else if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) { \ + } else if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \ + (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) { \ uint64_t now = now_mono_time(); \ if (lock_start) \ th_ctx->lock_wait_total += now - lock_start; \ @@ -386,7 +390,8 @@ typeof(expr) _expr = (expr); \ if (_expr == 0) { \ th_ctx->lock_level += bal; \ - if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) { \ + if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \ + (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) { \ if (_LK_ == _LK_UN && th_ctx->lock_level == 0) \ th_ctx->locked_total += now_mono_time() - th_ctx->lock_start_date; \ else if (_LK_ != _LK_UN && th_ctx->lock_level == 1) \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/tinfo-t.h new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/tinfo-t.h --- old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/tinfo-t.h 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/tinfo-t.h 2026-02-12 14:25:57.000000000 +0100 @@ -69,6 +69,8 @@ #define TH_FL_IN_DBG_HANDLER 0x00000100 /* thread currently in the debug signal handler */ #define TH_FL_IN_WDT_HANDLER 0x00000200 /* thread currently in the wdt signal handler */ #define TH_FL_IN_ANY_HANDLER 0x00000380 /* mask to test if the thread is in any signal handler */ +#define TH_FL_TASK_PROFILING_L 0x00000400 /* task profiling in locks (also requires TASK_PROFILING) */ +#define TH_FL_TASK_PROFILING_M 0x00000800 /* task profiling in mem alloc (also requires TASK_PROFILING) */ /* we have 4 buffer-wait queues, in highest to lowest emergency order */ #define DYNBUF_NBQ 4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/activity.c new/haproxy-3.3.3+git0.465d8e2fc/src/activity.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/activity.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/activity.c 2026-02-12 14:25:57.000000000 +0100 @@ -659,8 +659,20 @@ if (!(_HA_ATOMIC_LOAD(&th_ctx->flags) & TH_FL_TASK_PROFILING)) { if (unlikely((profiling & HA_PROF_TASKS_MASK) == HA_PROF_TASKS_ON || ((profiling & HA_PROF_TASKS_MASK) == HA_PROF_TASKS_AON && - swrate_avg(run_time, TIME_STATS_SAMPLES) >= up))) + swrate_avg(run_time, TIME_STATS_SAMPLES) >= up))) { + + if (profiling & HA_PROF_TASKS_LOCK) + _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_TASK_PROFILING_L); + else + _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_TASK_PROFILING_L); + + if (profiling & HA_PROF_TASKS_MEM) + _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_TASK_PROFILING_M); + else + _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_TASK_PROFILING_M); + _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_TASK_PROFILING); + } } else { if (unlikely((profiling & HA_PROF_TASKS_MASK) == HA_PROF_TASKS_OFF || ((profiling & HA_PROF_TASKS_MASK) == HA_PROF_TASKS_AOFF && @@ -692,26 +704,41 @@ } #endif // USE_MEMORY_PROFILING -/* config parser for global "profiling.tasks", accepts "on" or "off" */ +/* config parser for global "profiling.tasks", accepts "on", "off", 'auto", + * "lock", "no-lock", "memory", "no-memory". + */ static int cfg_parse_prof_tasks(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, const char *file, int line, char **err) { - if (too_many_args(1, args, err, NULL)) - return -1; + int arg; - if (strcmp(args[1], "on") == 0) { - profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_ON; - HA_ATOMIC_STORE(&prof_task_start_ns, now_ns); - } - else if (strcmp(args[1], "auto") == 0) { - profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_AOFF; - HA_ATOMIC_STORE(&prof_task_start_ns, now_ns); + for (arg = 1; *args[arg]; arg++) { + if (strcmp(args[arg], "on") == 0) { + profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_ON; + HA_ATOMIC_STORE(&prof_task_start_ns, now_ns); + } + else if (strcmp(args[arg], "auto") == 0) { + profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_AOFF; + HA_ATOMIC_STORE(&prof_task_start_ns, now_ns); + } + else if (strcmp(args[arg], "off") == 0) + profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_OFF; + else if (strcmp(args[arg], "lock") == 0) + profiling |= HA_PROF_TASKS_LOCK; + else if (strcmp(args[arg], "no-lock") == 0) + profiling &= ~HA_PROF_TASKS_LOCK; + else if (strcmp(args[arg], "memory") == 0) + profiling |= HA_PROF_TASKS_MEM; + else if (strcmp(args[arg], "no-memory") == 0) + profiling &= ~HA_PROF_TASKS_MEM; + else + break; } - else if (strcmp(args[1], "off") == 0) - profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_OFF; - else { - memprintf(err, "'%s' expects either 'on', 'auto', or 'off' but got '%s'.", args[0], args[1]); + + /* either no arg or invalid arg */ + if (arg == 1 || *args[arg]) { + memprintf(err, "'%s' expects a combination of either 'on', 'auto', 'off', 'lock', 'no-lock', 'memory', or 'no-memory', but got '%s'.", args[0], args[arg]); return -1; } return 0; @@ -720,6 +747,8 @@ /* parse a "set profiling" command. It always returns 1. */ static int cli_parse_set_profiling(char **args, char *payload, struct appctx *appctx, void *private) { + int arg; + if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) return 1; @@ -765,52 +794,66 @@ if (strcmp(args[2], "tasks") != 0) return cli_err(appctx, "Expects either 'tasks' or 'memory'.\n"); - if (strcmp(args[3], "on") == 0) { - unsigned int old = profiling; - int i; - - while (!_HA_ATOMIC_CAS(&profiling, &old, (old & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_ON)) - ; - - HA_ATOMIC_STORE(&prof_task_start_ns, now_ns); - HA_ATOMIC_STORE(&prof_task_stop_ns, 0); - - /* also flush current profiling stats */ - for (i = 0; i < SCHED_ACT_HASH_BUCKETS; i++) { - HA_ATOMIC_STORE(&sched_activity[i].calls, 0); - HA_ATOMIC_STORE(&sched_activity[i].cpu_time, 0); - HA_ATOMIC_STORE(&sched_activity[i].lat_time, 0); - HA_ATOMIC_STORE(&sched_activity[i].lkw_time, 0); - HA_ATOMIC_STORE(&sched_activity[i].lkd_time, 0); - HA_ATOMIC_STORE(&sched_activity[i].mem_time, 0); - HA_ATOMIC_STORE(&sched_activity[i].func, NULL); - HA_ATOMIC_STORE(&sched_activity[i].caller, NULL); - } - } - else if (strcmp(args[3], "auto") == 0) { - unsigned int old = profiling; - unsigned int new; - - do { - if ((old & HA_PROF_TASKS_MASK) >= HA_PROF_TASKS_AON) - new = (old & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_AON; - else - new = (old & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_AOFF; - } while (!_HA_ATOMIC_CAS(&profiling, &old, new)); + for (arg = 3; *args[arg]; arg++) { + if (strcmp(args[arg], "on") == 0) { + unsigned int old = profiling; + int i; - HA_ATOMIC_STORE(&prof_task_start_ns, now_ns); - HA_ATOMIC_STORE(&prof_task_stop_ns, 0); - } - else if (strcmp(args[3], "off") == 0) { - unsigned int old = profiling; - while (!_HA_ATOMIC_CAS(&profiling, &old, (old & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_OFF)) - ; + while (!_HA_ATOMIC_CAS(&profiling, &old, (old & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_ON)) + ; + + HA_ATOMIC_STORE(&prof_task_start_ns, now_ns); + HA_ATOMIC_STORE(&prof_task_stop_ns, 0); + + /* also flush current profiling stats */ + for (i = 0; i < SCHED_ACT_HASH_BUCKETS; i++) { + HA_ATOMIC_STORE(&sched_activity[i].calls, 0); + HA_ATOMIC_STORE(&sched_activity[i].cpu_time, 0); + HA_ATOMIC_STORE(&sched_activity[i].lat_time, 0); + HA_ATOMIC_STORE(&sched_activity[i].lkw_time, 0); + HA_ATOMIC_STORE(&sched_activity[i].lkd_time, 0); + HA_ATOMIC_STORE(&sched_activity[i].mem_time, 0); + HA_ATOMIC_STORE(&sched_activity[i].func, NULL); + HA_ATOMIC_STORE(&sched_activity[i].caller, NULL); + } + } + else if (strcmp(args[arg], "auto") == 0) { + unsigned int old = profiling; + unsigned int new; + + do { + if ((old & HA_PROF_TASKS_MASK) >= HA_PROF_TASKS_AON) + new = (old & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_AON; + else + new = (old & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_AOFF; + } while (!_HA_ATOMIC_CAS(&profiling, &old, new)); - if (HA_ATOMIC_LOAD(&prof_task_start_ns)) - HA_ATOMIC_STORE(&prof_task_stop_ns, now_ns); + HA_ATOMIC_STORE(&prof_task_start_ns, now_ns); + HA_ATOMIC_STORE(&prof_task_stop_ns, 0); + } + else if (strcmp(args[arg], "off") == 0) { + unsigned int old = profiling; + while (!_HA_ATOMIC_CAS(&profiling, &old, (old & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_OFF)) + ; + + if (HA_ATOMIC_LOAD(&prof_task_start_ns)) + HA_ATOMIC_STORE(&prof_task_stop_ns, now_ns); + } + else if (strcmp(args[arg], "lock") == 0) + HA_ATOMIC_OR(&profiling, HA_PROF_TASKS_LOCK); + else if (strcmp(args[arg], "no-lock") == 0) + HA_ATOMIC_AND(&profiling, ~HA_PROF_TASKS_LOCK); + else if (strcmp(args[arg], "memory") == 0) + HA_ATOMIC_OR(&profiling, HA_PROF_TASKS_MEM); + else if (strcmp(args[arg], "no-memory") == 0) + HA_ATOMIC_AND(&profiling, ~HA_PROF_TASKS_MEM); + else + break; // unknown arg } - else - return cli_err(appctx, "Expects 'on', 'auto', or 'off'.\n"); + + /* either no arg or invalid one */ + if (arg == 3 || *args[arg]) + return cli_err(appctx, "Expects a combination of either 'on', 'auto', 'off', 'lock', 'no-lock', 'memory' or 'no-memory'.\n"); return 1; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/backend.c new/haproxy-3.3.3+git0.465d8e2fc/src/backend.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/backend.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/backend.c 2026-02-12 14:25:57.000000000 +0100 @@ -576,9 +576,20 @@ /* compare the new server to the previous best choice and pick * the one with the least currently served requests. */ - if (prev && prev != curr && - curr->served * prev->cur_eweight > prev->served * curr->cur_eweight) - curr = prev; + if (prev && prev != curr) { + uint64_t wcurr = (uint64_t)curr->served * prev->cur_eweight; + uint64_t wprev = (uint64_t)prev->served * curr->cur_eweight; + + if (wcurr > wprev) + curr = prev; + else if (wcurr == wprev && curr->counters.shared.tg[tgid - 1] && prev->counters.shared.tg[tgid - 1]) { + /* same load: pick the lowest weighted request rate */ + wcurr = read_freq_ctr_period_estimate(&curr->counters._sess_per_sec, MS_TO_TICKS(1000)); + wprev = read_freq_ctr_period_estimate(&prev->counters._sess_per_sec, MS_TO_TICKS(1000)); + if (wprev * curr->cur_eweight < wcurr * prev->cur_eweight) + curr = prev; + } + } } while (--draws > 0); /* if the selected server is full, pretend we have none so that we reach diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/cpu_topo.c new/haproxy-3.3.3+git0.465d8e2fc/src/cpu_topo.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/cpu_topo.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/cpu_topo.c 2026-02-12 14:25:57.000000000 +0100 @@ -640,7 +640,10 @@ { const struct ha_cpu_cluster *l = (const struct ha_cpu_cluster *)a; const struct ha_cpu_cluster *r = (const struct ha_cpu_cluster *)b; - return r->capa - l->capa; + + if (!r->nb_cores || !l->nb_cores) + return r->nb_cores - l->nb_cores; + return r->capa * l->nb_cores - l->capa * r->nb_cores; } /* re-order a cluster array by cluster index only */ @@ -1341,7 +1344,7 @@ capa = 0; for (cluster = 0; cluster < cpu_topo_maxcpus; cluster++) { - if (capa && ha_cpu_clusters[cluster].capa * 10 < ha_cpu_clusters[cluster].nb_cpu * capa * 8) { + if (capa && ha_cpu_clusters[cluster].capa * 10 < ha_cpu_clusters[cluster].nb_cores * capa * 8) { /* This cluster is made of cores delivering less than * 80% of the performance of those of the previous * cluster, previous one, we're not interested in @@ -1352,8 +1355,8 @@ ha_cpu_topo[cpu].st |= HA_CPU_F_IGNORED; } } - else if (ha_cpu_clusters[cluster].nb_cpu) - capa = ha_cpu_clusters[cluster].capa / ha_cpu_clusters[cluster].nb_cpu; + else if (ha_cpu_clusters[cluster].nb_cores) + capa = ha_cpu_clusters[cluster].capa / ha_cpu_clusters[cluster].nb_cores; else capa = 0; } @@ -1386,7 +1389,7 @@ capa = 0; for (cluster = cpu_topo_maxcpus - 1; cluster >= 0; cluster--) { - if (capa && ha_cpu_clusters[cluster].capa * 8 >= ha_cpu_clusters[cluster].nb_cpu * capa * 10) { + if (capa && ha_cpu_clusters[cluster].capa * 8 >= ha_cpu_clusters[cluster].nb_cores * capa * 10) { /* This cluster is made of cores each at last 25% faster * than those of the previous cluster, previous one, we're * not interested in using it. @@ -1396,8 +1399,8 @@ ha_cpu_topo[cpu].st |= HA_CPU_F_IGNORED; } } - else if (ha_cpu_clusters[cluster].nb_cpu) - capa = ha_cpu_clusters[cluster].capa / ha_cpu_clusters[cluster].nb_cpu; + else if (ha_cpu_clusters[cluster].nb_cores) + capa = ha_cpu_clusters[cluster].capa / ha_cpu_clusters[cluster].nb_cores; else capa = 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/haproxy.c new/haproxy-3.3.3+git0.465d8e2fc/src/haproxy.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/haproxy.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/haproxy.c 2026-02-12 14:25:57.000000000 +0100 @@ -1434,11 +1434,15 @@ len = strlen(progname); progname = strdup(progname); if (!progname) { - ha_alert("Cannot allocate memory for log_tag.\n"); + ha_alert("Cannot allocate memory for progname.\n"); exit(EXIT_FAILURE); } chunk_initlen(&global.log_tag, strdup(progname), len, len); + if (b_orig(&global.log_tag) == NULL) { + ha_alert("Cannot allocate memory for log_tag.\n"); + exit(EXIT_FAILURE); + } } /* handles program arguments. Very minimal parsing is performed, variables are @@ -2900,9 +2904,11 @@ if (thread_has_tasks()) activity[tid].wake_tasks++; else { - _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_SLEEPING); - _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_NOTIFIED); - __ha_barrier_atomic_store(); + unsigned int flags = _HA_ATOMIC_LOAD(&th_ctx->flags); + + while (unlikely(!HA_ATOMIC_CAS(&th_ctx->flags, &flags, (flags | TH_FL_SLEEPING) & ~TH_FL_NOTIFIED))) + __ha_cpu_relax(); + if (thread_has_tasks()) { activity[tid].wake_tasks++; _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/lb_chash.c new/haproxy-3.3.3+git0.465d8e2fc/src/lb_chash.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/lb_chash.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/lb_chash.c 2026-02-12 14:25:57.000000000 +0100 @@ -552,6 +552,32 @@ return srv; } +/* Allocates and initializes lb nodes for server <srv>. Returns < 0 on error. + * This is called by chash_init_server_tree() as well as from srv_alloc_lb() + * for runtime addition. + */ +int chash_server_init(struct server *srv) +{ + int node; + + srv->lb_nodes = calloc(srv->lb_nodes_tot, sizeof(*srv->lb_nodes)); + if (!srv->lb_nodes) + return -1; + + srv->lb_server_key = chash_compute_server_key(srv); + for (node = 0; node < srv->lb_nodes_tot; node++) { + srv->lb_nodes[node].server = srv; + srv->lb_nodes[node].node.key = chash_compute_node_key(srv, node); + } + return 0; +} + +/* Releases the allocated lb_nodes for this server */ +void chash_server_deinit(struct server *srv) +{ + ha_free(&srv->lb_nodes); +} + /* This function is responsible for building the active and backup trees for * consistent hashing. The servers receive an array of initialized nodes * with their assigned keys. It also sets p->lbprm.wdiv to the eweight to @@ -562,11 +588,12 @@ { struct server *srv; struct eb_root init_head = EB_ROOT; - int node; p->lbprm.set_server_status_up = chash_set_server_status_up; p->lbprm.set_server_status_down = chash_set_server_status_down; p->lbprm.update_server_eweight = chash_update_server_weight; + p->lbprm.server_init = chash_server_init; + p->lbprm.server_deinit = chash_server_deinit; p->lbprm.server_take_conn = NULL; p->lbprm.server_drop_conn = NULL; @@ -588,17 +615,11 @@ srv->lb_tree = (srv->flags & SRV_F_BACKUP) ? &p->lbprm.chash.bck : &p->lbprm.chash.act; srv->lb_nodes_tot = srv->uweight * BE_WEIGHT_SCALE; srv->lb_nodes_now = 0; - srv->lb_nodes = calloc(srv->lb_nodes_tot, - sizeof(*srv->lb_nodes)); - if (!srv->lb_nodes) { + + if (chash_server_init(srv) < 0) { ha_alert("failed to allocate lb_nodes for server %s.\n", srv->id); return -1; } - srv->lb_server_key = chash_compute_server_key(srv); - for (node = 0; node < srv->lb_nodes_tot; node++) { - srv->lb_nodes[node].server = srv; - srv->lb_nodes[node].node.key = chash_compute_node_key(srv, node); - } if (srv_currently_usable(srv)) chash_queue_dequeue_srv(srv); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/pool.c new/haproxy-3.3.3+git0.465d8e2fc/src/pool.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/pool.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/pool.c 2026-02-12 14:25:57.000000000 +0100 @@ -794,7 +794,8 @@ if (unlikely(pool_cache_bytes > global.tune.pool_cache_size * 3 / 4)) { uint64_t mem_wait_start = 0; - if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) + if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) == + (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M))) mem_wait_start = now_mono_time(); if (ph->count >= 16 + pool_cache_count / 8 + CONFIG_HAP_POOL_CLUSTER_SIZE) @@ -957,7 +958,8 @@ uint64_t mem_wait_start = 0; int isolated = thread_isolated(); - if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) + if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) == + (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M))) mem_wait_start = now_mono_time(); if (!isolated) @@ -1019,7 +1021,8 @@ /* count allocation time only for cache misses */ uint64_t mem_wait_start = 0; - if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) + if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) == + (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M))) mem_wait_start = now_mono_time(); p = pool_alloc_nocache(pool, caller); @@ -1097,7 +1100,8 @@ global.tune.pool_cache_size < pool->size)) { uint64_t mem_wait_start = 0; - if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) + if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) == + (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M))) mem_wait_start = now_mono_time(); pool_free_nocache(pool, ptr); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/quic_frame.c new/haproxy-3.3.3+git0.465d8e2fc/src/quic_frame.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/quic_frame.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/quic_frame.c 2026-02-12 14:25:57.000000000 +0100 @@ -1166,7 +1166,12 @@ goto leave; } - quic_dec_int(&frm->type, pos, end); + if (!quic_dec_int(&frm->type, pos, end)) { + TRACE_ERROR("malformed frame type", QUIC_EV_CONN_PRSFRM, qc); + quic_set_connection_close(qc, quic_err_transport(QC_ERR_FRAME_ENCODING_ERROR)); + goto leave; + } + if (!quic_frame_type_is_known(frm->type)) { /* RFC 9000 12.4. Frames and Frame Types * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/quic_rx.c new/haproxy-3.3.3+git0.465d8e2fc/src/quic_rx.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/quic_rx.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/quic_rx.c 2026-02-12 14:25:57.000000000 +0100 @@ -1155,7 +1155,17 @@ if (frm) qc_frm_free(qc, &frm); - if (fast_retrans && qc->iel && qc->hel) { + /* RFC 9002 6.2.3. Speeding up Handshake Completion + * + * To speed up handshake completion under these conditions, an endpoint + * MAY, for a limited number of times per connection, send a packet + * containing unacknowledged CRYPTO data earlier than the PTO expiry, + * subject to the address validation limits in Section 8.1 of [QUIC- + * TRANSPORT]. Doing so at most once for each connection is adequate to + * quickly recover from a single packet loss. + */ + if (fast_retrans && !(qc->flags & QUIC_FL_CONN_HANDSHAKE_SPEED_UP) && + qc->iel && qc->hel) { struct quic_enc_level *iqel = qc->iel; struct quic_enc_level *hqel = qc->hel; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/quic_token.c new/haproxy-3.3.3+git0.465d8e2fc/src/quic_token.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/quic_token.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/quic_token.c 2026-02-12 14:25:57.000000000 +0100 @@ -129,6 +129,11 @@ goto err; } + if (tokenlen != QUIC_TOKEN_LEN) { + TRACE_ERROR("invalid token length", QUIC_EV_CONN_LPKT, qc); + goto err; + } + /* Generate the AAD. */ aadlen = ipaddrcpy(aad, &dgram->saddr); rand = token + tokenlen - QUIC_TOKEN_RAND_DLEN; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/server.c new/haproxy-3.3.3+git0.465d8e2fc/src/server.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/server.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/server.c 2026-02-12 14:25:57.000000000 +0100 @@ -3186,7 +3186,6 @@ free(srv->cc_algo); free(srv->tcp_md5sig); free(srv->addr_key); - free(srv->lb_nodes); counters_be_shared_drop(&srv->counters.shared); if (srv->log_target) { deinit_log_target(srv->log_target); @@ -5891,25 +5890,13 @@ */ static int srv_alloc_lb(struct server *sv, struct proxy *be) { - int node; - sv->lb_tree = (sv->flags & SRV_F_BACKUP) ? &be->lbprm.chash.bck : &be->lbprm.chash.act; sv->lb_nodes_tot = sv->uweight * BE_WEIGHT_SCALE; sv->lb_nodes_now = 0; - if (((be->lbprm.algo & (BE_LB_KIND | BE_LB_PARM)) == (BE_LB_KIND_RR | BE_LB_RR_RANDOM)) || - ((be->lbprm.algo & (BE_LB_KIND | BE_LB_HASH_TYPE)) == (BE_LB_KIND_HI | BE_LB_HASH_CONS))) { - sv->lb_nodes = calloc(sv->lb_nodes_tot, sizeof(*sv->lb_nodes)); - - if (!sv->lb_nodes) - return 0; - - for (node = 0; node < sv->lb_nodes_tot; node++) { - sv->lb_nodes[node].server = sv; - sv->lb_nodes[node].node.key = full_hash(sv->puid * SRV_EWGHT_RANGE + node); - } - } + if (be->lbprm.server_init && be->lbprm.server_init(sv) < 0) + return 0; // typically out of memory return 1; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/ssl_ckch.c new/haproxy-3.3.3+git0.465d8e2fc/src/ssl_ckch.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/ssl_ckch.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/ssl_ckch.c 2026-02-12 14:25:57.000000000 +0100 @@ -1488,6 +1488,25 @@ } /* + * return the default verify cert directory. + * + * It might provided by the SSL library or set in an environment variable + * (commonly SSL_CERT_DIR) + */ +const char *ha_default_cert_dir() +{ + const char *dir = NULL; + const char *certdir_varname = X509_get_default_cert_dir_env(); + + if (certdir_varname) + dir = getenv(certdir_varname); + if (dir == NULL) + dir = X509_get_default_cert_dir(); + + return dir; +} + +/* * Try to load a ca-file from disk into the ca-file cache. * <shuterror> allows you to to stop emitting the errors. * Return 0 upon error @@ -1516,7 +1535,7 @@ } if (strcmp(path, "@system-ca") == 0) { - dir = X509_get_default_cert_dir(); + dir = ha_default_cert_dir(); if (!dir) { if (!shuterror) ha_alert("Couldn't get the system CA directory from X509_get_default_cert_dir().\n"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/tools.c new/haproxy-3.3.3+git0.465d8e2fc/src/tools.c --- old/haproxy-3.3.2+git3.bc0fb5969/src/tools.c 2026-01-30 09:56:50.000000000 +0100 +++ new/haproxy-3.3.3+git0.465d8e2fc/src/tools.c 2026-02-12 14:25:57.000000000 +0100 @@ -987,6 +987,11 @@ int new_fd = -1; enum proto_type proto_type = 0; // to shut gcc warning int ctrl_type = 0; // to shut gcc warning + /* + * Indicates that we want to use an alternate protocol instead of the + * default one. + * Currently, only MPTCP is defined as an alternate protocol for TCP + */ int alt_proto = 0; portl = porth = porta = 0; @@ -1011,7 +1016,6 @@ ((opts & (PA_O_STREAM|PA_O_DGRAM)) == (PA_O_DGRAM|PA_O_STREAM) && (opts & PA_O_DEFAULT_DGRAM))) { proto_type = PROTO_TYPE_DGRAM; ctrl_type = SOCK_DGRAM; - alt_proto = 1; } else { proto_type = PROTO_TYPE_STREAM; ctrl_type = SOCK_STREAM; @@ -1026,7 +1030,6 @@ str2 += 6; proto_type = PROTO_TYPE_DGRAM; ctrl_type = SOCK_DGRAM; - alt_proto = 1; } else if (strncmp(str2, "quic+", 5) == 0) { str2 += 5; @@ -1043,7 +1046,6 @@ ss.ss_family = AF_UNIX; proto_type = PROTO_TYPE_DGRAM; ctrl_type = SOCK_DGRAM; - alt_proto = 1; } else if (strncmp(str2, "uxst@", 5) == 0) { str2 += 5; @@ -1089,7 +1091,6 @@ ss.ss_family = AF_INET; proto_type = PROTO_TYPE_DGRAM; ctrl_type = SOCK_DGRAM; - alt_proto = 1; } else if (strncmp(str2, "tcp6@", 5) == 0) { str2 += 5; @@ -1109,7 +1110,6 @@ ss.ss_family = AF_INET6; proto_type = PROTO_TYPE_DGRAM; ctrl_type = SOCK_DGRAM; - alt_proto = 1; } else if (strncmp(str2, "tcp@", 4) == 0) { str2 += 4; @@ -1129,7 +1129,6 @@ ss.ss_family = AF_UNSPEC; proto_type = PROTO_TYPE_DGRAM; ctrl_type = SOCK_DGRAM; - alt_proto = 1; } else if (strncmp(str2, "quic4@", 6) == 0) { str2 += 6; @@ -1399,6 +1398,8 @@ } if (proto || (opts & PA_O_CONNECT)) { + // if the socket type is SOCK_DGRAM, use by default an alternate protocol + alt_proto = alt_proto || (ctrl_type == SOCK_DGRAM); /* Note: if the caller asks for a proto, we must find one, * except if we inherit from a raw FD (family == AF_CUST_EXISTING_FD) * orif we return with an fqdn that will resolve later,
