mirror of
https://github.com/haproxy/haproxy.git
synced 2026-02-11 06:43:42 -05:00
Compare commits
66 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5f9c008b1 | ||
|
|
ea92b0ef01 | ||
|
|
2ac0d12790 | ||
|
|
c724693b95 | ||
|
|
e2631ee5f7 | ||
|
|
a7b2353cb3 | ||
|
|
3b45beb465 | ||
|
|
64c5d45a26 | ||
|
|
62239539bf | ||
|
|
91a5b67b25 | ||
|
|
ecffaa6d5a | ||
|
|
a1db464c3e | ||
|
|
5dff6e439d | ||
|
|
d7cdd2c7f4 | ||
|
|
5753c14e84 | ||
|
|
3115eb82a6 | ||
|
|
07195a1af4 | ||
|
|
a603811aac | ||
|
|
e152913327 | ||
|
|
7ac5088c50 | ||
|
|
817003aa31 | ||
|
|
dc6cf224dd | ||
|
|
87ea407cce | ||
|
|
a8bc83bea5 | ||
|
|
2c8ad11b73 | ||
|
|
2a07dc9c24 | ||
|
|
9dd7cf769e | ||
|
|
bf7a2808fc | ||
|
|
9766211cf0 | ||
|
|
9e023ae930 | ||
|
|
68e9fb73fd | ||
|
|
143f5a5c0d | ||
|
|
b6bdb2553b | ||
|
|
3edf600859 | ||
|
|
cddeea58cd | ||
|
|
3674afe8a0 | ||
|
|
2527d9dcd1 | ||
|
|
f26562bcb7 | ||
|
|
abc1947e19 | ||
|
|
02e6375017 | ||
|
|
da728aa0f6 | ||
|
|
23e8ed6ea6 | ||
|
|
fa094d0b61 | ||
|
|
869a997a68 | ||
|
|
48d9c90ff2 | ||
|
|
35d63cc3c7 | ||
|
|
bb36836d76 | ||
|
|
a79a67b52f | ||
|
|
a9df6947b4 | ||
|
|
3ca2a83fc0 | ||
|
|
cb3fd012cd | ||
|
|
bbab0ac4d0 | ||
|
|
6995fe60c3 | ||
|
|
0ea601127e | ||
|
|
0ebef67132 | ||
|
|
9b1faee4c9 | ||
|
|
d2ccc19fde | ||
|
|
f4cd1e74ba | ||
|
|
1a3252e956 | ||
|
|
e9e4821db5 | ||
|
|
4e7c07736a | ||
|
|
c267d24f57 | ||
|
|
a3e9a04435 | ||
|
|
be68ecc37d | ||
|
|
a66b4881d7 | ||
|
|
9e9083d0e2 |
54 changed files with 2526 additions and 1644 deletions
37
CHANGELOG
37
CHANGELOG
|
|
@ -1,6 +1,43 @@
|
|||
ChangeLog :
|
||||
===========
|
||||
|
||||
2026/02/04 : 3.4-dev4
|
||||
- BUG/MEDIUM: hlua: fix invalid lua_pcall() usage in hlua_traceback()
|
||||
- BUG/MINOR: hlua: consume error object if ignored after a failing lua_pcall()
|
||||
- BUG/MINOR: promex: Detach promex from the server on error dump its metrics dump
|
||||
- BUG/MEDIUM: mux-h1: Skip UNUSED htx block when formating the start line
|
||||
- BUG/MINOR: proto_tcp: Properly report support for HAVE_TCP_MD5SIG feature
|
||||
- BUG/MINOR: config: check capture pool creations for failures
|
||||
- BUG/MINOR: stick-tables: abort startup on stk_ctr pool creation failure
|
||||
- MEDIUM: pools: better check for size rounding overflow on registration
|
||||
- DOC: reg-tests: update VTest upstream link in the starting guide
|
||||
- BUG/MINOR: ssl: Properly manage alloc failures in SSL passphrase callback
|
||||
- BUG/MINOR: ssl: Encrypted keys could not be loaded when given alongside certificate
|
||||
- MINOR: ssl: display libssl errors on private key loading
|
||||
- BUG/MAJOR: applet: Don't call I/O handler if the applet was shut
|
||||
- MINOR: ssl: allow to disable certificate compression
|
||||
- BUG/MINOR: ssl: fix error message of tune.ssl.certificate-compression
|
||||
- DOC: config: mention some possible TLS versions restrictions for kTLS
|
||||
- OPTIM: server: move queueslength in server struct
|
||||
- OPTIM: proxy: separate queues fields from served
|
||||
- OPTIM: server: get rid of the last use of _ha_barrier_full()
|
||||
- DOC: config: mention that idle connection sharing is per thread-group
|
||||
- MEDIUM: h1: strictly verify quoting in chunk extensions
|
||||
- BUG/MINOR: config/ssl: fix spelling of "expose-experimental-directives"
|
||||
- BUG/MEDIUM: ssl: fix msg callbacks on QUIC connections
|
||||
- MEDIUM: ssl: remove connection from msg callback args
|
||||
- MEDIUM: ssl: porting to X509_STORE_get1_objects() for OpenSSL 4.0
|
||||
- REGTESTS: ssl: make reg-tests compatible with OpenSSL 4.0
|
||||
- DOC: internals: cleanup few typos in master-worker documentation
|
||||
- BUG/MEDIUM: applet: Fix test on shut flags for legacy applets
|
||||
- MINOR: quic: Fix build with USE_QUIC_OPENSSL_COMPAT
|
||||
- MEDIUM: tcpcheck: add post-80 option for mysql-check to support MySQL 8.x
|
||||
- BUG/MEDIUM: threads: Atomically set TH_FL_SLEEPING and clr FL_NOTIFIED
|
||||
- BUG/MINOR: cpu-topo: count cores not cpus to distinguish core types
|
||||
- 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
|
||||
|
||||
2026/01/22 : 3.4-dev3
|
||||
- BUILD: ssl: strchr definition changed in C23
|
||||
- BUILD: tools: memchr definition changed in C23
|
||||
|
|
|
|||
2
VERDATE
2
VERDATE
|
|
@ -1,2 +1,2 @@
|
|||
$Format:%ci$
|
||||
2026/01/22
|
||||
2026/02/04
|
||||
|
|
|
|||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
3.4-dev3
|
||||
3.4-dev4
|
||||
|
|
|
|||
|
|
@ -1255,7 +1255,7 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
|||
labels[lb_idx].value = ist2(sv->id, strlen(sv->id));
|
||||
|
||||
if (!stats_fill_sv_line(px, sv, 0, stats, ST_I_PX_MAX, &(ctx->field_num)))
|
||||
return -1;
|
||||
goto error;
|
||||
|
||||
if ((ctx->flags & PROMEX_FL_NO_MAINT_SRV) && (sv->cur_admin & SRV_ADMF_MAINT))
|
||||
goto next_sv;
|
||||
|
|
@ -1473,7 +1473,7 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
|||
|
||||
counters = EXTRA_COUNTERS_GET(sv->extra_counters, mod);
|
||||
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
|
||||
return -1;
|
||||
goto error;
|
||||
|
||||
val = stats[ctx->field_num + ctx->mod_field_num];
|
||||
metric.type = ((val.type == FN_GAUGE) ? PROMEX_MT_GAUGE : PROMEX_MT_COUNTER);
|
||||
|
|
@ -1515,6 +1515,10 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
|||
full:
|
||||
ret = 0;
|
||||
goto end;
|
||||
|
||||
error:
|
||||
watcher_detach(&ctx->srv_watch);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Dump metrics of module <mod>. It returns 1 on success, 0 if <out> is full and
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Configuration Manual
|
||||
----------------------
|
||||
version 3.4
|
||||
2026/01/22
|
||||
2026/02/04
|
||||
|
||||
|
||||
This document covers the configuration language as implemented in the version
|
||||
|
|
@ -1983,6 +1983,7 @@ The following keywords are supported in the "global" section :
|
|||
- tune.ssl.cachesize
|
||||
- tune.ssl.capture-buffer-size
|
||||
- tune.ssl.capture-cipherlist-size (deprecated)
|
||||
- tune.ssl.certificate-compression
|
||||
- tune.ssl.default-dh-param
|
||||
- tune.ssl.force-private-cache
|
||||
- tune.ssl.hard-maxrecord
|
||||
|
|
@ -4004,7 +4005,7 @@ profiling.memory { on | off }
|
|||
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
|
||||
|
|
@ -4015,6 +4016,18 @@ profiling.tasks { auto | on | off }
|
|||
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
|
||||
|
|
@ -4526,7 +4539,11 @@ tune.idle-pool.shared { on | off }
|
|||
disabling this option without setting a conservative value on "pool-low-conn"
|
||||
for all servers relying on connection reuse to achieve a high performance
|
||||
level, otherwise connections might be closed very often as the thread count
|
||||
increases.
|
||||
increases. Note that in any case, connections are only shared between threads
|
||||
of the same thread group. This means that systems with many NUMA nodes may
|
||||
show slightly more persistent connections while machines with unified caches
|
||||
and many CPU cores per node may experience higher CPU usage. In the latter
|
||||
case, the "max-thread-per-group" tunable may be used to improve the behavior.
|
||||
|
||||
tune.idletimer <timeout>
|
||||
Sets the duration after which HAProxy will consider that an empty buffer is
|
||||
|
|
@ -5310,6 +5327,22 @@ tune.ssl.capture-cipherlist-size <number> (deprecated)
|
|||
formats. If the value is 0 (default value) the capture is disabled,
|
||||
otherwise a buffer is allocated for each SSL/TLS connection.
|
||||
|
||||
tune.ssl.certificate-compression { auto | off }
|
||||
This setting allows to configure the certificate compression support which is
|
||||
an extension (RFC 8879) to TLS 1.3.
|
||||
|
||||
When set to "auto" it uses the default value of the TLS library.
|
||||
|
||||
With "off" it tries to explicitely disable the support of the feature.
|
||||
HAProxy won't try to send compressed certificates anymore nor accept
|
||||
compressed certificates.
|
||||
|
||||
Configures both backend and frontend sides.
|
||||
|
||||
This keyword is supported by OpenSSL >= 3.2.0.
|
||||
|
||||
The default value is auto.
|
||||
|
||||
tune.ssl.default-dh-param <number>
|
||||
Sets the maximum size of the Diffie-Hellman parameters used for generating
|
||||
the ephemeral/temporary Diffie-Hellman key in case of DHE key exchange. The
|
||||
|
|
@ -6262,8 +6295,16 @@ balance url_param <param> [check_post]
|
|||
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
|
||||
|
||||
|
|
@ -10800,7 +10841,7 @@ no option logasap
|
|||
logging.
|
||||
|
||||
|
||||
option mysql-check [ user <username> [ { post-41 | pre-41 } ] ]
|
||||
option mysql-check [ user <username> [ { post-41 | pre-41 | post-80 } ] ]
|
||||
Use MySQL health checks for server testing
|
||||
|
||||
May be used in the following contexts: tcp
|
||||
|
|
@ -10813,6 +10854,12 @@ option mysql-check [ user <username> [ { post-41 | pre-41 } ] ]
|
|||
server.
|
||||
post-41 Send post v4.1 client compatible checks (the default)
|
||||
pre-41 Send pre v4.1 client compatible checks
|
||||
post-80 Send post v8.0 client compatible checks with CLIENT_PLUGIN_AUTH
|
||||
capability set and mysql_native_password as the authentication
|
||||
plugin. Use this option when connecting to MySQL 8.0+ servers
|
||||
where the health check user is created with mysql_native_password
|
||||
authentication. Example:
|
||||
CREATE USER 'haproxy'@'%' IDENTIFIED WITH mysql_native_password BY '';
|
||||
|
||||
If you specify a username, the check consists of sending two MySQL packet,
|
||||
one Client Authentication packet, and one QUIT packet, to correctly close
|
||||
|
|
@ -17203,7 +17250,9 @@ interface <interface>
|
|||
ktls <on|off> [ EXPERIMENTAL ]
|
||||
Enables or disables ktls for those sockets. If enabled, kTLS will be used
|
||||
if the kernel supports it and the cipher is compatible. This is only
|
||||
available on Linux kernel 4.17 and above.
|
||||
available on Linux kernel 4.17 and above. Please note that some network
|
||||
drivers and/or TLS stacks might restrict kTLS usage to TLS v1.2 only. See
|
||||
also "force-tlsv12".
|
||||
|
||||
label <label>
|
||||
Sets an optional label for these sockets. It could be used group sockets by
|
||||
|
|
@ -18306,7 +18355,10 @@ hash-key <key>
|
|||
|
||||
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".
|
||||
|
|
@ -18318,7 +18370,9 @@ hash-key <key>
|
|||
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
|
||||
|
|
@ -18463,9 +18517,10 @@ See also: "option tcp-check", "option httpchk"
|
|||
ktls <on|off> [ EXPERIMENTAL ]
|
||||
May be used in the following contexts: tcp, http, log, peers, ring
|
||||
|
||||
Enables or disables ktls for those sockets. If enabled, kTLS will be used
|
||||
if the kernel supports it and the cipher is compatible.
|
||||
This is only available on Linux.
|
||||
Enables or disables ktls for those sockets. If enabled, kTLS will be used if
|
||||
the kernel supports it and the cipher is compatible. This is only available
|
||||
on Linux 4.17 and above. Please note that some network drivers and/or TLS
|
||||
stacks might restrict kTLS usage to TLS v1.2 only. See also "force-tlsv12".
|
||||
|
||||
log-bufsize <bufsize>
|
||||
May be used in the following contexts: log
|
||||
|
|
@ -21196,9 +21251,9 @@ ip.fp([<mode>])
|
|||
can be used to distinguish between multiple apparently identical hosts. The
|
||||
real-world use case is to refine the identification of misbehaving hosts
|
||||
between a shared IP address to avoid blocking legitimate users when only one
|
||||
is misbehaving and needs to be blocked. The converter builds a 7-byte binary
|
||||
block based on the input. The bytes of the fingerprint are arranged like
|
||||
this:
|
||||
is misbehaving and needs to be blocked. The converter builds a 8-byte minimum
|
||||
binary block based on the input. The bytes of the fingerprint are arranged
|
||||
like this:
|
||||
- byte 0: IP TOS field (see ip.tos)
|
||||
- byte 1:
|
||||
- bit 7: IPv6 (1) / IPv4 (0)
|
||||
|
|
@ -21213,10 +21268,13 @@ ip.fp([<mode>])
|
|||
- bits 3..0: TCP window scaling + 1 (1..15) / 0 (no WS advertised)
|
||||
- byte 3..4: tcp.win
|
||||
- byte 5..6: tcp.options.mss, or zero if absent
|
||||
- byte 7: 1 bit per present TCP option, with options 2 to 8 being mapped to
|
||||
bits 0..6 respectively, and bit 7 indicating the presence of any
|
||||
option from 9 to 255.
|
||||
|
||||
The <mode> argument permits to append more information to the fingerprint. By
|
||||
default, when the <mode> argument is not set or is zero, the fingerprint is
|
||||
solely made of the 7 bytes described above. If <mode> is specified as another
|
||||
solely made of the 8 bytes described above. If <mode> is specified as another
|
||||
value, it then corresponds to the sum of the following values, and the
|
||||
respective components will be concatenated to the fingerprint, in the order
|
||||
below:
|
||||
|
|
@ -21226,7 +21284,7 @@ ip.fp([<mode>])
|
|||
- 4: the source IP address is appended to the fingerprint, which adds
|
||||
4 bytes for IPv4 and 16 for IPv6.
|
||||
|
||||
Example: make a 12..24 bytes fingerprint using the base FP, the TTL and the
|
||||
Example: make a 13..25 bytes fingerprint using the base FP, the TTL and the
|
||||
source address (1+4=5):
|
||||
|
||||
frontend test
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ default init, this was controversial but fedora and archlinux already uses it.
|
|||
At this time HAProxy still had a multi-process model, and the way haproxy is
|
||||
working was incompatible with the daemon mode.
|
||||
|
||||
Systemd is compatible with traditionnal forking services, but somehow HAProxy
|
||||
Systemd is compatible with traditional forking services, but somehow HAProxy
|
||||
is different. To work correctly, systemd needs a main PID, this is the PID of
|
||||
the process that systemd will supervises.
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ However the wrapper suffered from several problems:
|
|||
|
||||
### mworker V1
|
||||
|
||||
HAProxy 1.8 got ride of the wrapper which was replaced by the master worker
|
||||
HAProxy 1.8 got rid of the wrapper which was replaced by the master worker
|
||||
mode. This first version was basically a reintegration of the wrapper features
|
||||
within HAProxy. HAProxy is launched with the -W flag, read the configuration and
|
||||
then fork. In mworker mode, the master is usually launched as a root process,
|
||||
|
|
@ -86,7 +86,7 @@ retrieved automatically.
|
|||
The master is supervising the workers, when a current worker (not a previous one
|
||||
from before the reload) is exiting without being asked for a reload, the master
|
||||
will emit an "exit-on-failure" error and will kill every workers with a SIGTERM
|
||||
and exits with the same error code than the failed master, this behavior can be
|
||||
and exits with the same error code than the failed worker, this behavior can be
|
||||
changed by using the "no exit-on-failure" option in the global section.
|
||||
|
||||
While the master is supervising the workers using the wait() function, the
|
||||
|
|
@ -186,8 +186,8 @@ number that can be found in HAPROXY_PROCESSES. With this change the stats socket
|
|||
in the configuration is less useful and everything can be done from the master
|
||||
CLI.
|
||||
|
||||
With 2.7, the reload mecanism of the master CLI evolved, with previous versions,
|
||||
this mecanism was asynchronous, so once the `reload` command was received, the
|
||||
With 2.7, the reload mechanism of the master CLI evolved, with previous versions,
|
||||
this mechanism was asynchronous, so once the `reload` command was received, the
|
||||
master would reload, the active master CLI connection was closed, and there was
|
||||
no way to return a status as a response to the `reload` command. To achieve a
|
||||
synchronous reload, a dedicated sockpair is used, one side uses a master CLI
|
||||
|
|
@ -208,3 +208,38 @@ starts with -st to achieve a hard stop on the previous worker.
|
|||
Version 3.0 got rid of the libsystemd dependencies for sd_notify() after the
|
||||
events of xz/openssh, the function is now implemented directly in haproxy in
|
||||
src/systemd.c.
|
||||
|
||||
### mworker V3
|
||||
|
||||
This version was implemented with HAProxy 3.1, the goal was to stop parsing and
|
||||
applying the configuration in the master process.
|
||||
|
||||
One of the caveats of the previous implementation was that the parser could take
|
||||
a lot of time, and the master process would be stuck in the parser instead of
|
||||
handling its polling loop, signals etc. Some parts of the configuration parsing
|
||||
could also be less reliable with third-party code (EXTRA_OBJS), it could, for
|
||||
example, allow opening FDs and not closing them before the reload which
|
||||
would crash the master after a few reloads.
|
||||
|
||||
The startup of the master-worker was reorganized this way:
|
||||
|
||||
- the "discovery" mode, which is a lighter configuration parsing step, only
|
||||
applies the configuration which need to be effective for the master process.
|
||||
For example, "master-worker", "mworker-max-reloads" and less than 20 other
|
||||
keywords that are identified by KWF_DISCOVERY in the code. It is really fast
|
||||
as it don't need all the configuration to be applied in the master process.
|
||||
|
||||
- the master will then fork a worker, with a PROC_O_INIT flag. This worker has
|
||||
a temporary sockpair connected to the master CLI. Once the worker is forked,
|
||||
the master initializes its configuration and starts its polling loop.
|
||||
|
||||
- The newly forked worker will try to parse the configuration, which could
|
||||
result in a failure (exit 1), or any bad error code. In case of success, the
|
||||
worker will send a "READY" message to the master CLI then close this FD. At
|
||||
this step everything was initialized and the worker can enter its polling
|
||||
loop.
|
||||
|
||||
- The master then waits for the worker, it could:
|
||||
* receive the READY message over the mCLI, resulting in a successful loading
|
||||
of haproxy
|
||||
* receive a SIGCHLD, meaning the worker exited and couldn't load
|
||||
|
|
|
|||
|
|
@ -1725,6 +1725,30 @@ add acl [@<ver>] <acl> <pattern>
|
|||
This command cannot be used if the reference <acl> is a name also used with
|
||||
a map. In this case, the "add map" command must be used instead.
|
||||
|
||||
add backend <name> from <defproxy> [mode <mode>] [guid <guid>] [ EXPERIMENTAL ]
|
||||
Instantiate a new backend proxy with the name <name>.
|
||||
|
||||
Only TCP or HTTP proxies can be created. All of the settings are inherited
|
||||
from <defproxy> default proxy instance. By default, it is mandatory to
|
||||
specify the backend mode via the argument of the same name, unless <defproxy>
|
||||
already defines it explicitely. It is also possible to use an optional GUID
|
||||
argument if wanted.
|
||||
|
||||
Servers can be added via the command "add server". The backend is initialized
|
||||
in the unpublished state. Once considered ready for traffic, use "publish
|
||||
backend" to expose the newly created instance.
|
||||
|
||||
All named default proxies can be used, given that they validate the same
|
||||
inheritance rules applied during configuration parsing. There is some
|
||||
exceptions though, for example when the mode is neither TCP nor HTTP. Another
|
||||
exception is that it is not yet possible to use a default proxies which
|
||||
reference custom HTTP errors, for example via the errorfiles or http-rules
|
||||
keywords.
|
||||
|
||||
This command is restricted and can only be issued on sockets configured for
|
||||
level "admin". Moreover, this feature is still considered in development so it
|
||||
also requires experimental mode (see "experimental-mode on").
|
||||
|
||||
add map [@<ver>] <map> <key> <value>
|
||||
add map [@<ver>] <map> <payload>
|
||||
Add an entry into the map <map> to associate the value <value> to the key
|
||||
|
|
@ -2534,7 +2558,8 @@ set maxconn global <maxconn>
|
|||
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
|
||||
|
|
@ -2544,6 +2569,13 @@ set profiling { tasks | memory } { auto | on | off }
|
|||
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
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ vtest installation
|
|||
------------------------
|
||||
|
||||
To use vtest you will have to download and compile the recent vtest
|
||||
sources found at https://github.com/vtest/VTest.
|
||||
sources found at https://github.com/vtest/VTest2.
|
||||
|
||||
To compile vtest:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ struct lbprm {
|
|||
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 */
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ int backend_parse_balance(const char **args, char **err, struct proxy *curproxy)
|
|||
int tcp_persist_rdp_cookie(struct stream *s, struct channel *req, int an_bit);
|
||||
|
||||
int be_downtime(struct proxy *px);
|
||||
int be_supports_dynamic_srv(struct proxy *px, char **msg);
|
||||
void recount_servers(struct proxy *px);
|
||||
void update_backend_weight(struct proxy *px);
|
||||
|
||||
|
|
|
|||
|
|
@ -263,6 +263,8 @@ static inline int h1_parse_chunk_size(const struct buffer *buf, int start, int s
|
|||
const char *ptr_old = ptr;
|
||||
const char *end = b_wrap(buf);
|
||||
uint64_t chunk = 0;
|
||||
int backslash = 0;
|
||||
int quote = 0;
|
||||
|
||||
stop -= start; // bytes left
|
||||
start = stop; // bytes to transfer
|
||||
|
|
@ -327,13 +329,37 @@ static inline int h1_parse_chunk_size(const struct buffer *buf, int start, int s
|
|||
if (--stop == 0)
|
||||
return 0;
|
||||
|
||||
while (!HTTP_IS_CRLF(*ptr)) {
|
||||
/* The loop seeks the first CRLF or non-tab CTL char
|
||||
* and stops there. If a backslash/quote is active,
|
||||
* it's an error. If none, we assume it's the CRLF
|
||||
* and go back to the top of the loop checking for
|
||||
* CR then LF. This way CTLs, lone LF etc are handled
|
||||
* in the fallback path. This allows to protect
|
||||
* remotes against their own possibly non-compliant
|
||||
* chunk-ext parser which could mistakenly skip a
|
||||
* quoted CRLF. Chunk-ext are not used anyway, except
|
||||
* by attacks.
|
||||
*/
|
||||
while (!HTTP_IS_CTL(*ptr) || HTTP_IS_SPHT(*ptr)) {
|
||||
if (backslash)
|
||||
backslash = 0; // escaped char
|
||||
else if (*ptr == '\\' && quote)
|
||||
backslash = 1;
|
||||
else if (*ptr == '\\') // backslash not permitted outside quotes
|
||||
goto error;
|
||||
else if (*ptr == '"') // begin/end of quoted-pair
|
||||
quote = !quote;
|
||||
if (++ptr >= end)
|
||||
ptr = b_orig(buf);
|
||||
if (--stop == 0)
|
||||
return 0;
|
||||
}
|
||||
/* we have a CRLF now, loop above */
|
||||
|
||||
/* mismatched quotes / backslashes end here */
|
||||
if (quote || backslash)
|
||||
goto error;
|
||||
|
||||
/* CTLs (CRLF) fall to the common check */
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -147,14 +147,14 @@ __attribute__((constructor)) static void __initcb_##linenum() \
|
|||
#define _DECLARE_INITCALL(...) \
|
||||
__DECLARE_INITCALL(__VA_ARGS__)
|
||||
|
||||
/* This requires that function <function> is called with pointer argument
|
||||
* <argument> during init stage <stage> which must be one of init_stage.
|
||||
/* This requires that function <function> is called without arguments
|
||||
* during init stage <stage> which must be one of init_stage.
|
||||
*/
|
||||
#define INITCALL0(stage, function) \
|
||||
_DECLARE_INITCALL(stage, __LINE__, function, 0, 0, 0)
|
||||
|
||||
/* This requires that function <function> is called with pointer argument
|
||||
* <argument> during init stage <stage> which must be one of init_stage.
|
||||
* <arg1> during init stage <stage> which must be one of init_stage.
|
||||
*/
|
||||
#define INITCALL1(stage, function, arg1) \
|
||||
_DECLARE_INITCALL(stage, __LINE__, function, arg1, 0, 0)
|
||||
|
|
|
|||
|
|
@ -380,6 +380,14 @@ static inline unsigned long ERR_peek_error_func(const char **func)
|
|||
|
||||
#endif
|
||||
|
||||
#if (HA_OPENSSL_VERSION_NUMBER >= 0x40000000L) && !defined(OPENSSL_IS_AWSLC) && !defined(LIBRESSL_VERSION_NUMBER) && !defined(USE_OPENSSL_WOLFSSL)
|
||||
# define X509_STORE_getX_objects(x) X509_STORE_get1_objects(x)
|
||||
# define sk_X509_OBJECT_popX_free(x, y) sk_X509_OBJECT_pop_free(x,y)
|
||||
#else
|
||||
# define X509_STORE_getX_objects(x) X509_STORE_get0_objects(x)
|
||||
# define sk_X509_OBJECT_popX_free(x, y) ({})
|
||||
#endif
|
||||
|
||||
#if (HA_OPENSSL_VERSION_NUMBER >= 0x1010000fL) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x2070200fL)
|
||||
#define __OPENSSL_110_CONST__ const
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ struct pool_registration {
|
|||
struct list list; /* link element */
|
||||
const char *name; /* name of the pool */
|
||||
const char *file; /* where the pool is declared */
|
||||
ullong size; /* expected object size */
|
||||
unsigned int line; /* line in the file where the pool is declared, 0 if none */
|
||||
unsigned int size; /* expected object size */
|
||||
unsigned int flags; /* MEM_F_* */
|
||||
unsigned int type_align; /* type-imposed alignment; 0=unspecified */
|
||||
unsigned int align; /* expected alignment; 0=unspecified */
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ unsigned long long pool_total_allocated(void);
|
|||
unsigned long long pool_total_used(void);
|
||||
void pool_flush(struct pool_head *pool);
|
||||
void pool_gc(struct pool_head *pool_ctx);
|
||||
struct pool_head *create_pool_with_loc(const char *name, unsigned int size, unsigned int align,
|
||||
struct pool_head *create_pool_with_loc(const char *name, ullong size, unsigned int align,
|
||||
unsigned int flags, const char *file, unsigned int line);
|
||||
struct pool_head *create_pool_from_reg(const char *name, struct pool_registration *reg);
|
||||
void create_pool_callback(struct pool_head **ptr, char *name, struct pool_registration *reg);
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ enum PR_SRV_STATE_FILE {
|
|||
/* Proxy flags */
|
||||
#define PR_FL_DISABLED 0x01 /* The proxy was disabled in the configuration (not at runtime) */
|
||||
#define PR_FL_STOPPED 0x02 /* The proxy was stopped */
|
||||
#define PR_FL_READY 0x04 /* The proxy is ready to be used (initialized and configured) */
|
||||
#define PR_FL_DEF_EXPLICIT_MODE 0x04 /* Proxy mode is explicitely defined - only used for defaults instance */
|
||||
#define PR_FL_EXPLICIT_REF 0x08 /* The default proxy is explicitly referenced by another proxy */
|
||||
#define PR_FL_IMPLICIT_REF 0x10 /* The default proxy is implicitly referenced by another proxy */
|
||||
#define PR_FL_PAUSED 0x20 /* The proxy was paused at run time (reversible) */
|
||||
|
|
@ -508,10 +508,16 @@ struct proxy {
|
|||
EXTRA_COUNTERS(extra_counters_be);
|
||||
|
||||
THREAD_ALIGN();
|
||||
unsigned int queueslength; /* Sum of the length of each queue */
|
||||
/* these ones change all the time */
|
||||
int served; /* # of active sessions currently being served */
|
||||
int totpend; /* total number of pending connections on this instance (for stats) */
|
||||
unsigned int feconn, beconn; /* # of active frontend and backends streams */
|
||||
|
||||
THREAD_ALIGN();
|
||||
/* these ones are only changed when queues are involved, but checked
|
||||
* all the time.
|
||||
*/
|
||||
unsigned int queueslength; /* Sum of the length of each queue */
|
||||
int totpend; /* total number of pending connections on this instance (for stats) */
|
||||
};
|
||||
|
||||
struct switching_rule {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ extern unsigned int error_snapshot_id; /* global ID assigned to each error then
|
|||
extern struct ceb_root *proxy_by_name; /* tree of proxies sorted by name */
|
||||
extern struct list defaults_list; /* all defaults proxies list */
|
||||
|
||||
extern unsigned int dynpx_next_id;
|
||||
|
||||
extern const struct cfg_opt cfg_opts[];
|
||||
extern const struct cfg_opt cfg_opts2[];
|
||||
extern const struct cfg_opt cfg_opts3[];
|
||||
|
|
@ -59,6 +61,7 @@ void deinit_proxy(struct proxy *p);
|
|||
void free_proxy(struct proxy *p);
|
||||
const char *proxy_cap_str(int cap);
|
||||
const char *proxy_mode_str(int mode);
|
||||
enum pr_mode str_to_proxy_mode(const char *mode);
|
||||
const char *proxy_find_best_option(const char *word, const char **extra);
|
||||
uint proxy_get_next_id(uint from);
|
||||
void proxy_store_name(struct proxy *px);
|
||||
|
|
@ -74,8 +77,7 @@ void defaults_px_destroy_all_unref(void);
|
|||
void defaults_px_detach(struct proxy *px);
|
||||
void defaults_px_ref_all(void);
|
||||
void defaults_px_unref_all(void);
|
||||
|
||||
void proxy_ref_defaults(struct proxy *px, struct proxy *defpx);
|
||||
int proxy_ref_defaults(struct proxy *px, struct proxy *defpx, char **errmsg);
|
||||
void proxy_unref_defaults(struct proxy *px);
|
||||
int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char **errmsg);
|
||||
struct proxy *alloc_new_proxy(const char *name, unsigned int cap,
|
||||
|
|
@ -97,6 +99,7 @@ int resolve_stick_rule(struct proxy *curproxy, struct sticking_rule *mrule);
|
|||
void free_stick_rules(struct list *rules);
|
||||
void free_server_rules(struct list *srules);
|
||||
int proxy_init_per_thr(struct proxy *px);
|
||||
int proxy_finalize(struct proxy *px, int *err_code);
|
||||
|
||||
/*
|
||||
* This function returns a string containing the type of the proxy in a format
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@
|
|||
#define QUIC_OPENSSL_COMPAT_CLIENT_APPLICATION "CLIENT_TRAFFIC_SECRET_0"
|
||||
#define QUIC_OPENSSL_COMPAT_SERVER_APPLICATION "SERVER_TRAFFIC_SECRET_0"
|
||||
|
||||
void quic_tls_compat_msg_callback(struct connection *conn,
|
||||
int write_p, int version, int content_type,
|
||||
void quic_tls_compat_msg_callback(int write_p, int version, int content_type,
|
||||
const void *buf, size_t len, SSL *ssl);
|
||||
int quic_tls_compat_init(struct bind_conf *bind_conf, SSL_CTX *ctx);
|
||||
void quic_tls_compat_keylog_callback(const SSL *ssl, const char *line);
|
||||
|
|
|
|||
|
|
@ -383,7 +383,6 @@ struct server {
|
|||
unsigned next_eweight; /* next pending eweight to commit */
|
||||
unsigned cumulative_weight; /* weight of servers prior to this one in the same group, for chash balancing */
|
||||
int maxqueue; /* maximum number of pending connections allowed */
|
||||
unsigned int queueslength; /* Sum of the length of each queue */
|
||||
int shard; /* shard (in peers protocol context only) */
|
||||
int log_bufsize; /* implicit ring bufsize (for log server only - in log backend) */
|
||||
|
||||
|
|
@ -406,6 +405,7 @@ struct server {
|
|||
unsigned int max_used_conns; /* Max number of used connections (the counter is reset at each connection purges */
|
||||
unsigned int est_need_conns; /* Estimate on the number of needed connections (max of curr and previous max_used) */
|
||||
unsigned int curr_sess_idle_conns; /* Current number of idle connections attached to a session instead of idle/safe trees. */
|
||||
unsigned int queueslength; /* Sum of the length of each queue */
|
||||
|
||||
/* elements only used during boot, do not perturb and plug the hole */
|
||||
struct guid_node guid; /* GUID global tree node */
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ void ssl_store_delete_cafile_entry(struct cafile_entry *ca_e);
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ struct issuer_chain {
|
|||
|
||||
struct connection;
|
||||
|
||||
typedef void (*ssl_sock_msg_callback_func)(struct connection *conn,
|
||||
typedef void (*ssl_sock_msg_callback_func)(
|
||||
int write_p, int version, int content_type,
|
||||
const void *buf, size_t len, SSL *ssl);
|
||||
|
||||
|
|
@ -338,6 +338,8 @@ struct global_ssl {
|
|||
int renegotiate; /* Renegotiate mode (SSL_RENEGOTIATE_ flag) */
|
||||
char **passphrase_cmd;
|
||||
int passphrase_cmd_args_cnt;
|
||||
|
||||
unsigned int certificate_compression:1; /* allow to explicitely disable certificate compression */
|
||||
};
|
||||
|
||||
/* The order here matters for picking a default context,
|
||||
|
|
@ -361,6 +363,7 @@ struct passphrase_cb_data {
|
|||
const char *path;
|
||||
struct ckch_data *ckch_data;
|
||||
int passphrase_idx;
|
||||
int callback_called;
|
||||
};
|
||||
|
||||
#endif /* USE_OPENSSL */
|
||||
|
|
|
|||
|
|
@ -362,15 +362,19 @@ static inline unsigned long thread_isolated()
|
|||
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; \
|
||||
|
|
@ -384,7 +388,8 @@ static inline unsigned long thread_isolated()
|
|||
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) \
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ enum {
|
|||
#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
|
||||
|
|
|
|||
84
reg-tests/proxy/cli_add_backend.vtc
Normal file
84
reg-tests/proxy/cli_add_backend.vtc
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
varnishtest "Add backend via cli"
|
||||
|
||||
feature ignore_unknown_macro
|
||||
|
||||
haproxy hsrv -conf {
|
||||
global
|
||||
.if feature(THREAD)
|
||||
thread-groups 1
|
||||
.endif
|
||||
|
||||
defaults
|
||||
mode http
|
||||
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
|
||||
frontend fe
|
||||
bind "fd@${fe}"
|
||||
http-request return status 200
|
||||
} -start
|
||||
|
||||
haproxy h1 -conf {
|
||||
global
|
||||
.if feature(THREAD)
|
||||
thread-groups 1
|
||||
.endif
|
||||
|
||||
defaults
|
||||
mode http
|
||||
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
|
||||
frontend fe
|
||||
bind "fd@${feS}"
|
||||
force-be-switch if { req.hdr("x-admin") "1" }
|
||||
use_backend %[req.hdr(x-be)]
|
||||
|
||||
defaults def
|
||||
|
||||
defaults def_http
|
||||
mode http
|
||||
} -start
|
||||
|
||||
client c1 -connect ${h1_feS_sock} {
|
||||
txreq -hdr "x-be: be"
|
||||
rxresp
|
||||
expect resp.status == 503
|
||||
} -run
|
||||
|
||||
haproxy h1 -cli {
|
||||
# non existent backend
|
||||
send "experimental-mode on; add backend be from def"
|
||||
expect ~ "Mode is required"
|
||||
|
||||
send "experimental-mode on; add backend be from def_http"
|
||||
expect ~ "New backend registered."
|
||||
|
||||
send "add server be/srv ${hsrv_fe_addr}:${hsrv_fe_port}"
|
||||
expect ~ "New server registered."
|
||||
send "enable server be/srv"
|
||||
expect ~ ".*"
|
||||
}
|
||||
|
||||
client c1 -connect ${h1_feS_sock} {
|
||||
txreq -hdr "x-be: be"
|
||||
rxresp
|
||||
expect resp.status == 503
|
||||
|
||||
txreq -hdr "x-be: be" -hdr "x-admin: 1"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
} -run
|
||||
|
||||
haproxy h1 -cli {
|
||||
send "publish backend be"
|
||||
expect ~ "Backend published."
|
||||
}
|
||||
|
||||
client c1 -connect ${h1_feS_sock} {
|
||||
txreq -hdr "x-be: be"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
} -run
|
||||
|
|
@ -51,7 +51,7 @@ haproxy h1 -cli {
|
|||
|
||||
# invalid load-balancing algo
|
||||
send "add server other/s1 ${s1_addr}:${s1_port}"
|
||||
expect ~ "Backend must use a dynamic load balancing to support dynamic servers."
|
||||
expect ~ "backend 'other' uses a non dynamic load balancing method"
|
||||
|
||||
# invalid mux proto
|
||||
send "add server other2/s1 ${s1_addr}:${s1_port} proto h2"
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ haproxy h1 -cli {
|
|||
send "show ssl ca-file ${testdir}/certs/set_cafile_interCA1.crt:2"
|
||||
expect !~ ".*SHA1 FingerPrint: 4FFF535278883264693CEA72C4FAD13F995D0098"
|
||||
send "show ssl ca-file ${testdir}/certs/set_cafile_interCA1.crt:2"
|
||||
expect ~ ".*SHA1 FingerPrint: 3D3D1D10AD74A8135F05A818E10E5FA91433954D"
|
||||
expect ~ ".*SHA1 FingerPrint: 3D3D1D10AD74A8135F05A818E10E5FA91433954D|5F8DAE4B2099A09F9BDDAFD7E9D900F0CE49977C"
|
||||
}
|
||||
|
||||
client c1 -connect ${h1_clearverifiedlst_sock} {
|
||||
|
|
|
|||
|
|
@ -86,9 +86,7 @@ haproxy h1 -cli {
|
|||
expect ~ "\\*${testdir}/certs/interCA2_crl_empty.pem"
|
||||
|
||||
send "show ssl crl-file \\*${testdir}/certs/interCA2_crl_empty.pem"
|
||||
expect ~ "Revoked Certificates:"
|
||||
send "show ssl crl-file \\*${testdir}/certs/interCA2_crl_empty.pem:1"
|
||||
expect ~ "Serial Number: 1008"
|
||||
expect ~ "Revoked Certificates:\n.*Serial Number: 1008"
|
||||
}
|
||||
|
||||
# This connection should still succeed since the transaction was not committed
|
||||
|
|
|
|||
149
src/activity.c
149
src/activity.c
|
|
@ -659,8 +659,20 @@ void activity_count_runtime(uint32_t run_time)
|
|||
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 @@ static int cfg_parse_prof_memory(char **args, int section_type, struct proxy *cu
|
|||
}
|
||||
#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);
|
||||
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], "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[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 @@ static int cfg_parse_prof_tasks(char **args, int section_type, struct proxy *cur
|
|||
/* 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 @@ static int cli_parse_set_profiling(char **args, char *payload, struct appctx *ap
|
|||
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;
|
||||
for (arg = 3; *args[arg]; arg++) {
|
||||
if (strcmp(args[arg], "on") == 0) {
|
||||
unsigned int old = profiling;
|
||||
int i;
|
||||
|
||||
while (!_HA_ATOMIC_CAS(&profiling, &old, (old & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_ON))
|
||||
;
|
||||
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);
|
||||
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);
|
||||
/* 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;
|
||||
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));
|
||||
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));
|
||||
|
||||
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))
|
||||
;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
13
src/applet.c
13
src/applet.c
|
|
@ -848,7 +848,12 @@ struct task *task_run_applet(struct task *t, void *context, unsigned int state)
|
|||
|
||||
input = applet_output_data(app);
|
||||
output = co_data(oc);
|
||||
app->applet->fct(app);
|
||||
|
||||
/* Don't call I/O handler if the applet was shut (release callback was
|
||||
* already called)
|
||||
*/
|
||||
if (!se_fl_test(app->sedesc, SE_FL_SHR | SE_FL_SHW))
|
||||
app->applet->fct(app);
|
||||
|
||||
TRACE_POINT(APPLET_EV_PROCESS, app);
|
||||
|
||||
|
|
@ -945,7 +950,11 @@ struct task *task_process_applet(struct task *t, void *context, unsigned int sta
|
|||
applet_need_more_data(app);
|
||||
applet_have_no_more_data(app);
|
||||
|
||||
app->applet->fct(app);
|
||||
/* Don't call I/O handler if the applet was shut (release callback was
|
||||
* already called)
|
||||
*/
|
||||
if (!applet_fl_test(app, APPCTX_FL_SHUTDOWN))
|
||||
app->applet->fct(app);
|
||||
|
||||
TRACE_POINT(APPLET_EV_PROCESS, app);
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
#include <haproxy/task.h>
|
||||
#include <haproxy/ticks.h>
|
||||
#include <haproxy/time.h>
|
||||
#include <haproxy/tools.h>
|
||||
#include <haproxy/trace.h>
|
||||
|
||||
#define TRACE_SOURCE &trace_strm
|
||||
|
|
@ -576,9 +577,20 @@ struct server *get_server_rnd(struct stream *s, const struct server *avoid)
|
|||
/* 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 && prev->counters.shared.tg) {
|
||||
/* 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
|
||||
|
|
@ -3044,6 +3056,27 @@ int be_downtime(struct proxy *px) {
|
|||
return ns_to_sec(now_ns) - px->last_change + px->down_time;
|
||||
}
|
||||
|
||||
/* Checks if <px> backend supports the addition of servers at runtime. Either a
|
||||
* backend or a defaults proxy are supported. If proxy is incompatible, <msg>
|
||||
* will be allocated to contain a textual explaination.
|
||||
*/
|
||||
int be_supports_dynamic_srv(struct proxy *px, char **msg)
|
||||
{
|
||||
if (px->lbprm.algo && !(px->lbprm.algo & BE_LB_PROP_DYN)) {
|
||||
memprintf(msg, "%s '%s' uses a non dynamic load balancing method",
|
||||
proxy_cap_str(px->cap), px->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (px->mode == PR_MODE_SYSLOG) {
|
||||
memprintf(msg, "%s '%s' uses mode log",
|
||||
proxy_cap_str(px->cap), px->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns a string containing the balancing
|
||||
* mode of the proxy in a format suitable for stats.
|
||||
|
|
|
|||
|
|
@ -501,84 +501,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||
curproxy->conf.file_prev = file_prev;
|
||||
curproxy->conf.line_prev = line_prev;
|
||||
|
||||
if (curr_defproxy && (!LIST_ISEMPTY(&curr_defproxy->http_req_rules) ||
|
||||
!LIST_ISEMPTY(&curr_defproxy->http_res_rules) ||
|
||||
!LIST_ISEMPTY(&curr_defproxy->http_after_res_rules) ||
|
||||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.l4_rules) ||
|
||||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.l5_rules) ||
|
||||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.inspect_rules) ||
|
||||
!LIST_ISEMPTY(&curr_defproxy->tcp_rep.inspect_rules))) {
|
||||
/* If the current default proxy defines TCP/HTTP rules, the
|
||||
* current proxy will keep a reference on it. But some sanity
|
||||
* checks are performed first:
|
||||
*
|
||||
* - It cannot be used to init a defaults section
|
||||
* - It cannot be used to init a listen section
|
||||
* - It cannot be used to init backend and frontend sections at
|
||||
* same time. It can be used to init several sections of the
|
||||
* same type only.
|
||||
* - It cannot define L4/L5 TCP rules if it is used to init
|
||||
* backend sections.
|
||||
* - It cannot define 'tcp-response content' rules if it
|
||||
* is used to init frontend sections.
|
||||
*
|
||||
* If no error is found, refcount of the default proxy is incremented.
|
||||
*/
|
||||
|
||||
/* Note: Add tcpcheck_rules too if unresolve args become allowed in defaults section */
|
||||
if (rc & PR_CAP_DEF) {
|
||||
ha_alert("parsing [%s:%d]: a defaults section cannot inherit from a defaults section defining TCP/HTTP rules (defaults section at %s:%d).\n",
|
||||
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
}
|
||||
else if ((rc & PR_CAP_LISTEN) == PR_CAP_LISTEN) {
|
||||
ha_alert("parsing [%s:%d]: a listen section cannot inherit from a defaults section defining TCP/HTTP rules.\n",
|
||||
file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
}
|
||||
else {
|
||||
char defcap = (curr_defproxy->cap & PR_CAP_LISTEN);
|
||||
|
||||
if ((defcap == PR_CAP_BE || defcap == PR_CAP_FE) && (rc & PR_CAP_LISTEN) != defcap) {
|
||||
ha_alert("parsing [%s:%d]: frontends and backends cannot inherit from the same defaults section"
|
||||
" if it defines TCP/HTTP rules (defaults section at %s:%d).\n",
|
||||
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
}
|
||||
else if (!(rc & PR_CAP_FE) && (!LIST_ISEMPTY(&curr_defproxy->tcp_req.l4_rules) ||
|
||||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.l5_rules))) {
|
||||
ha_alert("parsing [%s:%d]: a backend section cannot inherit from a defaults section defining"
|
||||
" 'tcp-request connection' or 'tcp-request session' rules (defaults section at %s:%d).\n",
|
||||
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
}
|
||||
else if (!(rc & PR_CAP_BE) && !LIST_ISEMPTY(&curr_defproxy->tcp_rep.inspect_rules)) {
|
||||
ha_alert("parsing [%s:%d]: a frontend section cannot inherit from a defaults section defining"
|
||||
" 'tcp-response content' rules (defaults section at %s:%d).\n",
|
||||
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
}
|
||||
else {
|
||||
curr_defproxy->cap = (curr_defproxy->cap & ~PR_CAP_LISTEN) | (rc & PR_CAP_LISTEN);
|
||||
proxy_ref_defaults(curproxy, curr_defproxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_defproxy && (curr_defproxy->tcpcheck_rules.flags & TCPCHK_RULES_PROTO_CHK) &&
|
||||
(curproxy->cap & PR_CAP_LISTEN) == PR_CAP_BE) {
|
||||
/* If the current default proxy defines tcpcheck rules, the
|
||||
* current proxy will keep a reference on it. but only if the
|
||||
* current proxy has the backend capability.
|
||||
*/
|
||||
proxy_ref_defaults(curproxy, curr_defproxy);
|
||||
}
|
||||
|
||||
if ((rc & PR_CAP_BE) && curr_defproxy && (curr_defproxy->nb_req_cap || curr_defproxy->nb_rsp_cap)) {
|
||||
ha_alert("parsing [%s:%d]: backend or defaults sections cannot inherit from a defaults section defining"
|
||||
" capptures (defaults section at %s:%d).\n",
|
||||
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
if (curr_defproxy) {
|
||||
err_code = proxy_ref_defaults(curproxy, curr_defproxy, &errmsg);
|
||||
if (err_code)
|
||||
ha_alert("parsing [%s:%d]: %s.\n", file, linenum, errmsg);
|
||||
}
|
||||
|
||||
if (rc & PR_CAP_DEF) {
|
||||
|
|
@ -707,23 +633,32 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||
goto out;
|
||||
}
|
||||
else if (strcmp(args[0], "mode") == 0) { /* sets the proxy mode */
|
||||
enum pr_mode mode;
|
||||
if (alertif_too_many_args(1, file, linenum, args, &err_code))
|
||||
goto out;
|
||||
|
||||
if (strcmp(args[1], "http") == 0) curproxy->mode = PR_MODE_HTTP;
|
||||
else if (strcmp(args[1], "tcp") == 0) curproxy->mode = PR_MODE_TCP;
|
||||
else if (strcmp(args[1], "log") == 0 && (curproxy->cap & PR_CAP_BE)) curproxy->mode = PR_MODE_SYSLOG;
|
||||
else if (strcmp(args[1], "spop") == 0 && (curproxy->cap & PR_CAP_BE)) curproxy->mode = PR_MODE_SPOP;
|
||||
else if (strcmp(args[1], "health") == 0) {
|
||||
if (unlikely(strcmp(args[1], "health") == 0)) {
|
||||
ha_alert("parsing [%s:%d] : 'mode health' doesn't exist anymore. Please use 'http-request return status 200' instead.\n", file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
else {
|
||||
|
||||
mode = str_to_proxy_mode(args[1]);
|
||||
if (!mode) {
|
||||
ha_alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
else if ((mode == PR_MODE_SYSLOG || mode == PR_MODE_SPOP) &&
|
||||
!(curproxy->cap & PR_CAP_BE)) {
|
||||
ha_alert("parsing [%s:%d] : mode %s is only applicable on proxies with backend capability.\n", file, linenum, proxy_mode_str(mode));
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
curproxy->mode = mode;
|
||||
if (curproxy->cap & PR_CAP_DEF)
|
||||
curproxy->flags |= PR_FL_DEF_EXPLICIT_MODE;
|
||||
}
|
||||
else if (strcmp(args[0], "id") == 0) {
|
||||
struct proxy *conflict;
|
||||
|
|
|
|||
|
|
@ -496,6 +496,36 @@ static int ssl_parse_global_keylog(char **args, int section_type, struct proxy *
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Allow to explicitely disable certificate compression when set to "off" */
|
||||
#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
|
||||
static int ssl_parse_certificate_compression(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;
|
||||
|
||||
if (strcmp(args[1], "auto") == 0)
|
||||
global_ssl.certificate_compression = 1;
|
||||
else if (strcmp(args[1], "off") == 0)
|
||||
global_ssl.certificate_compression = 0;
|
||||
else {
|
||||
memprintf(err, "'%s' expects either 'auto' or 'off' but got '%s'.", args[0], args[1]); return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int ssl_parse_certificate_compression(char **args, int section_type, struct proxy *curpx,
|
||||
const struct proxy *defpx, const char *file, int line,
|
||||
char **err)
|
||||
{
|
||||
memprintf(err, "'%s' is not supported by your TLS library. "
|
||||
"It is known to work only with OpenSSL >= 3.2.0.", args[0]);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* parse "ssl.force-private-cache".
|
||||
* Returns <0 on alert, >0 on warning, 0 on success.
|
||||
*/
|
||||
|
|
@ -943,7 +973,7 @@ static int ssl_bind_parse_ktls(char **args, int cur_arg, struct proxy *px, struc
|
|||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
if (!experimental_directives_allowed) {
|
||||
memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directive'", args[cur_arg]);
|
||||
memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'", args[cur_arg]);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
if (!strcasecmp(args[cur_arg + 1], "on")) {
|
||||
|
|
@ -2020,7 +2050,7 @@ static int srv_parse_ktls(char **args, int *cur_arg, struct proxy *px, struct se
|
|||
}
|
||||
|
||||
if (!experimental_directives_allowed) {
|
||||
memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directive'", args[*cur_arg]);
|
||||
memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'", args[*cur_arg]);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
|
|
@ -2759,6 +2789,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
|||
{ CFG_GLOBAL, "ssl-security-level", ssl_parse_security_level },
|
||||
{ CFG_GLOBAL, "ssl-skip-self-issued-ca", ssl_parse_skip_self_issued_ca },
|
||||
{ CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int },
|
||||
{ CFG_GLOBAL, "tune.ssl.certificate-compression", ssl_parse_certificate_compression },
|
||||
{ CFG_GLOBAL, "tune.ssl.default-dh-param", ssl_parse_global_default_dh },
|
||||
{ CFG_GLOBAL, "tune.ssl.force-private-cache", ssl_parse_global_private_cache },
|
||||
{ CFG_GLOBAL, "tune.ssl.lifetime", ssl_parse_global_lifetime },
|
||||
|
|
|
|||
1357
src/cfgparse.c
1357
src/cfgparse.c
File diff suppressed because it is too large
Load diff
|
|
@ -686,7 +686,10 @@ int _cmp_cluster_avg_capa(const void *a, const void *b)
|
|||
{
|
||||
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 */
|
||||
|
|
@ -1669,7 +1672,7 @@ static int cpu_policy_performance(int policy, int tmin, int tmax, int gmin, int
|
|||
|
||||
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
|
||||
|
|
@ -1680,8 +1683,8 @@ static int cpu_policy_performance(int policy, int tmin, int tmax, int gmin, int
|
|||
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;
|
||||
}
|
||||
|
|
@ -1714,7 +1717,7 @@ static int cpu_policy_efficiency(int policy, int tmin, int tmax, int gmin, int g
|
|||
|
||||
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.
|
||||
|
|
@ -1724,8 +1727,8 @@ static int cpu_policy_efficiency(int policy, int tmin, int tmax, int gmin, int g
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
32
src/h1_htx.c
32
src/h1_htx.c
|
|
@ -724,14 +724,42 @@ static size_t h1_parse_full_contig_chunks(struct h1m *h1m, struct htx **dsthtx,
|
|||
break;
|
||||
}
|
||||
else if (likely(end[ridx] == ';')) {
|
||||
int backslash = 0;
|
||||
int quote = 0;
|
||||
|
||||
/* chunk extension, ends at next CRLF */
|
||||
if (!++ridx)
|
||||
goto end_parsing;
|
||||
while (!HTTP_IS_CRLF(end[ridx])) {
|
||||
|
||||
/* The loop seeks the first CRLF or non-tab CTL char
|
||||
* and stops there. If a backslash/quote is active,
|
||||
* it's an error. If none, we assume it's the CRLF
|
||||
* and go back to the top of the loop checking for
|
||||
* CR then LF. This way CTLs, lone LF etc are handled
|
||||
* in the fallback path. This allows to protect
|
||||
* remotes against their own possibly non-compliant
|
||||
* chunk-ext parser which could mistakenly skip a
|
||||
* quoted CRLF. Chunk-ext are not used anyway, except
|
||||
* by attacks.
|
||||
*/
|
||||
while (!HTTP_IS_CTL(end[ridx]) || HTTP_IS_SPHT(end[ridx])) {
|
||||
if (backslash)
|
||||
backslash = 0; // escaped char
|
||||
else if (end[ridx] == '\\' && quote)
|
||||
backslash = 1;
|
||||
else if (end[ridx] == '\\') // backslash not permitted outside quotes
|
||||
goto parsing_error;
|
||||
else if (end[ridx] == '"') // begin/end of quoted-pair
|
||||
quote = !quote;
|
||||
if (!++ridx)
|
||||
goto end_parsing;
|
||||
}
|
||||
/* we have a CRLF now, loop above */
|
||||
|
||||
/* mismatched quotes / backslashes end here */
|
||||
if (quote || backslash)
|
||||
goto parsing_error;
|
||||
|
||||
/* CTLs (CRLF) fall to the common check */
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ struct global global = {
|
|||
#endif
|
||||
/* by default allow clients which use a privileged port for TCP only */
|
||||
.clt_privileged_ports = HA_PROTO_TCP,
|
||||
.maxthrpertgroup = MAX_THREADS_PER_GROUP,
|
||||
/* others NULL OK */
|
||||
};
|
||||
|
||||
|
|
@ -1435,11 +1436,15 @@ static void init_early(int argc, char **argv)
|
|||
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
|
||||
|
|
@ -2918,9 +2923,11 @@ void run_poll_loop()
|
|||
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);
|
||||
|
|
|
|||
13
src/hlua.c
13
src/hlua.c
|
|
@ -273,6 +273,7 @@ static const char *hlua_tostring_safe(lua_State *L, int index)
|
|||
break;
|
||||
default:
|
||||
/* error was caught */
|
||||
lua_pop(L, 1); // consume the lua object pushed on the stack since we ignore it
|
||||
return NULL;
|
||||
}
|
||||
return str;
|
||||
|
|
@ -323,6 +324,7 @@ static const char *hlua_pushvfstring_safe(lua_State *L, const char *fmt, va_list
|
|||
break;
|
||||
default:
|
||||
/* error was caught */
|
||||
lua_pop(L, 1); // consume the lua object pushed on the stack since we ignore it
|
||||
dst = NULL;
|
||||
}
|
||||
va_end(cpy_argp);
|
||||
|
|
@ -870,6 +872,7 @@ void hlua_unref(lua_State *L, int ref)
|
|||
__LJMP static int _hlua_traceback(lua_State *L)
|
||||
{
|
||||
lua_Debug *ar = lua_touserdata(L, 1);
|
||||
int ret;
|
||||
|
||||
/* Fill fields:
|
||||
* 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
|
||||
|
|
@ -877,7 +880,10 @@ __LJMP static int _hlua_traceback(lua_State *L)
|
|||
* 'n': fills in the field name and namewhat;
|
||||
* 't': fills in the field istailcall;
|
||||
*/
|
||||
return lua_getinfo(L, "Slnt", ar);
|
||||
ret = lua_getinfo(L, "Slnt", ar);
|
||||
if (!ret)
|
||||
WILL_LJMP(luaL_error(L, "unexpected"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -896,10 +902,11 @@ const char *hlua_traceback(lua_State *L, const char* sep)
|
|||
lua_pushlightuserdata(L, &ar);
|
||||
|
||||
/* safe getinfo */
|
||||
switch (lua_pcall(L, 1, 1, 0)) {
|
||||
switch (lua_pcall(L, 1, 0, 0)) {
|
||||
case LUA_OK:
|
||||
break;
|
||||
default:
|
||||
lua_pop(L, 1); // consume the lua object pushed on the stack since we ignore it
|
||||
goto end; // abort
|
||||
}
|
||||
|
||||
|
|
@ -998,6 +1005,7 @@ static int hlua_pusherror(lua_State *L, const char *fmt, ...)
|
|||
case LUA_OK:
|
||||
break;
|
||||
default:
|
||||
lua_pop(L, 1); // consume the lua object pushed on the stack since we ignore it
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
|
|
@ -10188,6 +10196,7 @@ static int hlua_new_event_sub_safe(lua_State *L, struct event_hdl_sub *sub)
|
|||
return 1;
|
||||
default:
|
||||
/* error was caught */
|
||||
lua_pop(L, 1); // consume the lua object pushed on the stack since we ignore it
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -960,6 +960,12 @@ static enum act_parse_ret parse_http_req_capture(const char **args, int *orig_ar
|
|||
hdr->namelen = 0;
|
||||
hdr->len = len;
|
||||
hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
|
||||
if (!hdr->pool) {
|
||||
memprintf(err, "out of memory");
|
||||
free(hdr);
|
||||
release_sample_expr(expr);
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
hdr->index = px->nb_req_cap++;
|
||||
|
||||
px->req_cap = hdr;
|
||||
|
|
|
|||
|
|
@ -552,6 +552,32 @@ struct server *chash_get_next_server(struct proxy *p, struct server *srvtoavoid)
|
|||
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 @@ int chash_init_server_tree(struct proxy *p)
|
|||
{
|
||||
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 @@ int chash_init_server_tree(struct proxy *p)
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -2488,8 +2488,10 @@ static size_t h1_make_reqline(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
|
|||
goto end;
|
||||
type = htx_get_blk_type(blk);
|
||||
sz = htx_get_blksz(blk);
|
||||
if (type == HTX_BLK_UNUSED)
|
||||
if (type == HTX_BLK_UNUSED) {
|
||||
htx_remove_blk(htx, blk);
|
||||
continue;
|
||||
}
|
||||
if (type != HTX_BLK_REQ_SL || sz > count)
|
||||
goto error;
|
||||
break;
|
||||
|
|
@ -2577,8 +2579,10 @@ static size_t h1_make_stline(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
|
|||
type = htx_get_blk_type(blk);
|
||||
sz = htx_get_blksz(blk);
|
||||
|
||||
if (type == HTX_BLK_UNUSED)
|
||||
if (type == HTX_BLK_UNUSED) {
|
||||
htx_remove_blk(htx, blk);
|
||||
continue;
|
||||
}
|
||||
if (type != HTX_BLK_RES_SL || sz > count)
|
||||
goto error;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -652,8 +652,8 @@ static int sample_conv_tcp_win(const struct arg *arg_p, struct sample *smp, void
|
|||
/* Builds a binary fingerprint of the IP+TCP input contents that are supposed
|
||||
* to rely essentially on the client stack's settings. This can be used for
|
||||
* example to selectively block bad behaviors at one IP address without
|
||||
* blocking others. The resulting fingerprint is a binary block of 56 to 376
|
||||
* bytes long (56 being the fixed part and the rest depending on the provided
|
||||
* blocking others. The resulting fingerprint is a binary block of 64 to 384
|
||||
* bits long (64 being the fixed part and the rest depending on the provided
|
||||
* TCP extensions).
|
||||
*/
|
||||
static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *private)
|
||||
|
|
@ -668,6 +668,7 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
|||
uchar tcpflags;
|
||||
uchar tcplen;
|
||||
uchar tcpws;
|
||||
uchar opts;
|
||||
ushort pktlen;
|
||||
ushort tcpwin;
|
||||
ushort tcpmss;
|
||||
|
|
@ -719,8 +720,8 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
|||
else
|
||||
return 0;
|
||||
|
||||
/* prepare trash to contain at least 7 bytes */
|
||||
trash->data = 7;
|
||||
/* prepare trash to contain at least 8 bytes */
|
||||
trash->data = 8;
|
||||
|
||||
/* store the TOS in the FP's first byte */
|
||||
trash->area[0] = iptos;
|
||||
|
|
@ -763,9 +764,11 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
|||
(tcpflags >> 6 << 0); // CWR, ECE
|
||||
|
||||
tcpmss = tcpws = 0;
|
||||
opts = 0;
|
||||
ofs = 20;
|
||||
while (ofs < tcplen) {
|
||||
size_t next;
|
||||
uchar opt;
|
||||
|
||||
if (smp->data.u.str.area[ofs] == 0) // kind0=end of options
|
||||
break;
|
||||
|
|
@ -782,17 +785,24 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
|||
break;
|
||||
|
||||
/* option is complete, take a copy of it */
|
||||
if (mode & 2) // mode & 2: append tcp.options_list
|
||||
trash->area[trash->data++] = smp->data.u.str.area[ofs];
|
||||
opt = smp->data.u.str.area[ofs];
|
||||
|
||||
if (smp->data.u.str.area[ofs] == 2 /* MSS */) {
|
||||
if (mode & 2) // mode & 2: append tcp.options_list
|
||||
trash->area[trash->data++] = opt;
|
||||
|
||||
if (opt == 2 /* MSS */) {
|
||||
tcpmss = read_n16(smp->data.u.str.area + ofs + 2);
|
||||
}
|
||||
else if (smp->data.u.str.area[ofs] == 3 /* WS */) {
|
||||
else if (opt == 3 /* WS */) {
|
||||
tcpws = (uchar)smp->data.u.str.area[ofs + 2];
|
||||
/* output from 1 to 15, thus 0=not found */
|
||||
tcpws = tcpws > 14 ? 15 : tcpws + 1;
|
||||
}
|
||||
|
||||
/* keep a presence mask of opts 2..8 and others */
|
||||
if (opt >= 2)
|
||||
opts |= 1 << (opt < 9 ? opt - 2 : 7);
|
||||
|
||||
ofs = next;
|
||||
}
|
||||
|
||||
|
|
@ -803,6 +813,9 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
|||
write_n16(trash->area + 3, tcpwin);
|
||||
write_n16(trash->area + 5, tcpmss);
|
||||
|
||||
/* the the bit mask of present options */
|
||||
trash->area[7] = opts;
|
||||
|
||||
/* mode 4: append source IP address */
|
||||
if (mode & 4) {
|
||||
iplen = (ipver == 4) ? 4 : 16;
|
||||
|
|
|
|||
34
src/pool.c
34
src/pool.c
|
|
@ -302,7 +302,7 @@ static int mem_should_fail(const struct pool_head *pool)
|
|||
* registration struct. Use create_pool() instead which does it for free.
|
||||
* The alignment will be stored as-is in the registration.
|
||||
*/
|
||||
struct pool_head *create_pool_with_loc(const char *name, unsigned int size,
|
||||
struct pool_head *create_pool_with_loc(const char *name, ullong size,
|
||||
unsigned int align, unsigned int flags,
|
||||
const char *file, unsigned int line)
|
||||
{
|
||||
|
|
@ -335,7 +335,8 @@ struct pool_head *create_pool_from_reg(const char *name, struct pool_registratio
|
|||
{
|
||||
unsigned int extra_mark, extra_caller, extra;
|
||||
unsigned int flags = reg->flags;
|
||||
unsigned int size = reg->size;
|
||||
ullong reg_size = reg->size; // copy of the originally requested size
|
||||
ullong size = reg_size;
|
||||
unsigned int alignment = reg->align;
|
||||
struct pool_head *pool = NULL;
|
||||
struct pool_head *entry;
|
||||
|
|
@ -374,6 +375,9 @@ struct pool_head *create_pool_from_reg(const char *name, struct pool_registratio
|
|||
extra_caller = (pool_debugging & POOL_DBG_CALLER) ? POOL_EXTRA_CALLER : 0;
|
||||
extra = extra_mark + extra_caller;
|
||||
|
||||
if (size > 0xFFFFFFFFULL || (size + extra) > 0xFFFFFFFFULL || (uint)(size + extra) < (uint)reg_size)
|
||||
goto ovf;
|
||||
|
||||
if (!(pool_debugging & POOL_DBG_NO_CACHE)) {
|
||||
/* we'll store two lists there, we need the room for this. Let's
|
||||
* make sure it's always OK even when including the extra word
|
||||
|
|
@ -392,7 +396,7 @@ struct pool_head *create_pool_from_reg(const char *name, struct pool_registratio
|
|||
*/
|
||||
if (!(flags & MEM_F_EXACT)) {
|
||||
align = (pool_debugging & POOL_DBG_TAG) ? sizeof(void *) : 16;
|
||||
size = ((size + align - 1) & -align);
|
||||
size = ((size + align - 1) & -(ullong)align);
|
||||
}
|
||||
|
||||
if (pool_debugging & POOL_DBG_BACKUP) {
|
||||
|
|
@ -402,6 +406,9 @@ struct pool_head *create_pool_from_reg(const char *name, struct pool_registratio
|
|||
extra += size;
|
||||
}
|
||||
|
||||
if (size > 0xFFFFFFFFULL || (size + extra) > 0xFFFFFFFFULL || (uint)(size + extra) < (uint)reg_size)
|
||||
goto ovf;
|
||||
|
||||
/* TODO: thread: we do not lock pool list for now because all pools are
|
||||
* created during HAProxy startup (so before threads creation) */
|
||||
start = &pools;
|
||||
|
|
@ -496,6 +503,11 @@ struct pool_head *create_pool_from_reg(const char *name, struct pool_registratio
|
|||
|
||||
fail:
|
||||
return pool;
|
||||
ovf:
|
||||
ha_alert("Failed to create pool '%s' of size '%llu': overflow detected due to too large "
|
||||
"a configured size and/or configured pool options. Aborting.\n",
|
||||
name, reg_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Tries to allocate an object for the pool <pool> using the system's allocator
|
||||
|
|
@ -794,7 +806,8 @@ void pool_put_to_cache(struct pool_head *pool, void *ptr, const void *caller)
|
|||
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 +970,8 @@ void pool_gc(struct pool_head *pool_ctx)
|
|||
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 +1033,8 @@ void *__pool_alloc(struct pool_head *pool, unsigned int flags)
|
|||
/* 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 +1112,8 @@ void __pool_free(struct pool_head *pool, void *ptr)
|
|||
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);
|
||||
|
|
@ -1428,7 +1444,7 @@ int dump_pools_info(struct appctx *appctx)
|
|||
struct pool_registration *reg;
|
||||
|
||||
list_for_each_entry(reg, &ctx->pool_info[i].entry->regs, list) {
|
||||
chunk_appendf(&trash, " > %-12s: size=%u flags=%#x align=%u", reg->name, reg->size, reg->flags, reg->align);
|
||||
chunk_appendf(&trash, " > %-12s: size=%llu flags=%#x align=%u", reg->name, reg->size, reg->flags, reg->align);
|
||||
if (reg->file && reg->line)
|
||||
chunk_appendf(&trash, " [%s:%u]", reg->file, reg->line);
|
||||
chunk_appendf(&trash, "\n");
|
||||
|
|
@ -1651,7 +1667,7 @@ void create_pool_callback(struct pool_head **ptr, char *name, struct pool_regist
|
|||
{
|
||||
*ptr = create_pool_from_reg(name, reg);
|
||||
if (!*ptr) {
|
||||
ha_alert("Failed to allocate pool '%s' of size %u : %s. Aborting.\n",
|
||||
ha_alert("Failed to allocate pool '%s' of size %llu : %s. Aborting.\n",
|
||||
name, reg->size, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1028,7 +1028,7 @@ static int tcp_get_info(struct connection *conn, long long int *info, int info_n
|
|||
|
||||
static void __proto_tcp_init(void)
|
||||
{
|
||||
#if defined(__linux__) && !defined(TCP_MD5SIG)
|
||||
#if defined(__linux__) && defined(TCP_MD5SIG)
|
||||
hap_register_feature("HAVE_TCP_MD5SIG");
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
1627
src/proxy.c
1627
src/proxy.c
File diff suppressed because it is too large
Load diff
|
|
@ -359,8 +359,7 @@ leave:
|
|||
}
|
||||
|
||||
/* Callback use to parse TLS messages for <ssl> TLS session. */
|
||||
void quic_tls_compat_msg_callback(struct connection *conn,
|
||||
int write_p, int version, int content_type,
|
||||
void quic_tls_compat_msg_callback(int write_p, int version, int content_type,
|
||||
const void *buf, size_t len, SSL *ssl)
|
||||
{
|
||||
unsigned int alert;
|
||||
|
|
|
|||
34
src/server.c
34
src/server.c
|
|
@ -3184,7 +3184,6 @@ void srv_free_params(struct server *srv)
|
|||
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);
|
||||
|
|
@ -5889,25 +5888,13 @@ static int cli_parse_enable_server(char **args, char *payload, struct appctx *ap
|
|||
*/
|
||||
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;
|
||||
}
|
||||
|
|
@ -6104,7 +6091,7 @@ static int cli_parse_add_server(char **args, char *payload, struct appctx *appct
|
|||
struct add_srv_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
|
||||
struct proxy *be;
|
||||
struct server *srv;
|
||||
char *be_name, *sv_name;
|
||||
char *be_name, *sv_name, *errmsg;
|
||||
int errcode, argc;
|
||||
int next_id;
|
||||
const int parse_flags = SRV_PARSE_DYNAMIC|SRV_PARSE_PARSE_ADDR;
|
||||
|
|
@ -6140,13 +6127,9 @@ static int cli_parse_add_server(char **args, char *payload, struct appctx *appct
|
|||
if (!be)
|
||||
return cli_err(appctx, "No such backend.\n");
|
||||
|
||||
if (!(be->lbprm.algo & BE_LB_PROP_DYN)) {
|
||||
cli_err(appctx, "Backend must use a dynamic load balancing to support dynamic servers.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (be->mode == PR_MODE_SYSLOG) {
|
||||
cli_err(appctx," Dynamic servers cannot be used with log backends.\n");
|
||||
errmsg = NULL;
|
||||
if (!be_supports_dynamic_srv(be, &errmsg)) {
|
||||
cli_dynerr(appctx, memprintf(&errmsg, "Backend does not support dynamic servers : %s.\n", errmsg));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -7416,10 +7399,9 @@ int srv_add_to_idle_list(struct server *srv, struct connection *conn, int is_saf
|
|||
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
||||
_HA_ATOMIC_INC(&srv->curr_idle_thr[tid]);
|
||||
|
||||
__ha_barrier_full();
|
||||
if ((volatile void *)srv->idle_node.node.leaf_p == NULL) {
|
||||
if (HA_ATOMIC_LOAD(&srv->idle_node.node.leaf_p) == NULL) {
|
||||
HA_SPIN_LOCK(OTHER_LOCK, &idle_conn_srv_lock);
|
||||
if ((volatile void *)srv->idle_node.node.leaf_p == NULL) {
|
||||
if (_HA_ATOMIC_LOAD(&srv->idle_node.node.leaf_p) == NULL) {
|
||||
srv->idle_node.key = tick_add(srv->pool_purge_delay,
|
||||
now_ms);
|
||||
eb32_insert(&idle_conn_srv, &srv->idle_node);
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ int ssl_sock_load_key_into_ckch(const char *path, char *buf, struct ckch_data *d
|
|||
BIO *in = NULL;
|
||||
int ret = 1;
|
||||
EVP_PKEY *key = NULL;
|
||||
struct passphrase_cb_data cb_data = { path, data, 0 };
|
||||
struct passphrase_cb_data cb_data = { path, data, 0, 0 };
|
||||
|
||||
if (buf) {
|
||||
/* reading from a buffer */
|
||||
|
|
@ -625,11 +625,13 @@ int ssl_sock_load_key_into_ckch(const char *path, char *buf, struct ckch_data *d
|
|||
*/
|
||||
do {
|
||||
key = PEM_read_bio_PrivateKey(in, NULL, ssl_sock_passwd_cb, &cb_data);
|
||||
} while (!key && cb_data.passphrase_idx != -1);
|
||||
} while (!key && cb_data.passphrase_idx != -1 && cb_data.callback_called);
|
||||
|
||||
if (key == NULL) {
|
||||
memprintf(err, "%sunable to load private key from file '%s'.\n",
|
||||
err && *err ? *err : "", path);
|
||||
unsigned long e = ERR_peek_last_error();
|
||||
|
||||
memprintf(err, "%sunable to load private key from file '%s' (%s).\n",
|
||||
err && *err ? *err : "", path, ERR_error_string(e, NULL));
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
|
@ -667,6 +669,7 @@ int ssl_sock_load_pem_into_ckch(const char *path, char *buf, struct ckch_data *d
|
|||
HASSL_DH *dh = NULL;
|
||||
STACK_OF(X509) *chain = NULL;
|
||||
struct issuer_chain *issuer_chain = NULL;
|
||||
struct passphrase_cb_data cb_data = { path, data, 0, 0 };
|
||||
|
||||
if (buf) {
|
||||
/* reading from a buffer */
|
||||
|
|
@ -691,8 +694,18 @@ int ssl_sock_load_pem_into_ckch(const char *path, char *buf, struct ckch_data *d
|
|||
}
|
||||
}
|
||||
|
||||
/* Read Private Key */
|
||||
key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
|
||||
/* Read Private Key
|
||||
* Since multiple private keys might have different passphrases that are
|
||||
* stored in a local cache, we want to try all the already known
|
||||
* passphrases first before raising an error. The passphrase_idx field
|
||||
* of the cb_data parameter will be modified in the callback and set to
|
||||
* -1 after the external passphrase tool is called.
|
||||
*/
|
||||
/* We don't know yet if the private key requires a password. */
|
||||
data->encrypted_privkey = 0;
|
||||
do {
|
||||
key = PEM_read_bio_PrivateKey(in, NULL, ssl_sock_passwd_cb, &cb_data);
|
||||
} while (!key && cb_data.passphrase_idx != -1 && cb_data.callback_called);
|
||||
/* no need to check for errors here, because the private key could be loaded later */
|
||||
|
||||
#ifndef OPENSSL_NO_DH
|
||||
|
|
@ -1332,7 +1345,7 @@ struct cafile_entry *ssl_store_dup_cafile_entry(struct cafile_entry *src)
|
|||
{
|
||||
struct cafile_entry *dst = NULL;
|
||||
X509_STORE *store = NULL;
|
||||
STACK_OF(X509_OBJECT) *objs;
|
||||
STACK_OF(X509_OBJECT) *objs = NULL;
|
||||
int i;
|
||||
|
||||
if (!src)
|
||||
|
|
@ -1344,7 +1357,7 @@ struct cafile_entry *ssl_store_dup_cafile_entry(struct cafile_entry *src)
|
|||
if (!store)
|
||||
goto err;
|
||||
|
||||
objs = X509_STORE_get0_objects(src->ca_store);
|
||||
objs = X509_STORE_getX_objects(src->ca_store);
|
||||
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
||||
X509 *cert;
|
||||
X509_CRL *crl;
|
||||
|
|
@ -1372,10 +1385,11 @@ struct cafile_entry *ssl_store_dup_cafile_entry(struct cafile_entry *src)
|
|||
}
|
||||
}
|
||||
dst = ssl_store_create_cafile_entry(src->path, store, src->type);
|
||||
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
return dst;
|
||||
|
||||
err:
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
X509_STORE_free(store);
|
||||
ha_free(&dst);
|
||||
|
||||
|
|
@ -1476,6 +1490,25 @@ end:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
|
@ -1483,13 +1516,13 @@ end:
|
|||
*/
|
||||
int __ssl_store_load_locations_file(char *path, int create_if_none, enum cafile_type type, int shuterror)
|
||||
{
|
||||
STACK_OF(X509_OBJECT) *objs = NULL;
|
||||
X509_STORE *store = ssl_store_get0_locations_file(path);
|
||||
|
||||
/* If this function is called by the CLI, we should not call the
|
||||
* X509_STORE_load_locations function because it performs forbidden disk
|
||||
* accesses. */
|
||||
if (!store && create_if_none) {
|
||||
STACK_OF(X509_OBJECT) *objs;
|
||||
int cert_count = 0;
|
||||
struct stat buf;
|
||||
struct cafile_entry *ca_e;
|
||||
|
|
@ -1505,7 +1538,7 @@ int __ssl_store_load_locations_file(char *path, int create_if_none, enum cafile_
|
|||
}
|
||||
|
||||
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");
|
||||
|
|
@ -1594,7 +1627,7 @@ scandir_err:
|
|||
}
|
||||
}
|
||||
|
||||
objs = X509_STORE_get0_objects(store);
|
||||
objs = X509_STORE_getX_objects(store);
|
||||
cert_count = sk_X509_OBJECT_num(objs);
|
||||
if (cert_count == 0) {
|
||||
if (!shuterror)
|
||||
|
|
@ -1608,9 +1641,11 @@ scandir_err:
|
|||
}
|
||||
ebst_insert(&cafile_tree, &ca_e->node);
|
||||
}
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
return (store != NULL);
|
||||
|
||||
err:
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
X509_STORE_free(store);
|
||||
store = NULL;
|
||||
return 0;
|
||||
|
|
@ -3781,7 +3816,7 @@ static int cli_io_handler_show_cafile_detail(struct appctx *appctx)
|
|||
struct buffer *out = alloc_trash_chunk();
|
||||
int i = 0;
|
||||
X509 *cert;
|
||||
STACK_OF(X509_OBJECT) *objs;
|
||||
STACK_OF(X509_OBJECT) *objs = NULL;
|
||||
int retval = 0;
|
||||
int ca_index = ctx->ca_index;
|
||||
int show_all = ctx->show_all;
|
||||
|
|
@ -3807,7 +3842,7 @@ static int cli_io_handler_show_cafile_detail(struct appctx *appctx)
|
|||
if (!cafile_entry->ca_store)
|
||||
goto end;
|
||||
|
||||
objs = X509_STORE_get0_objects(cafile_entry->ca_store);
|
||||
objs = X509_STORE_getX_objects(cafile_entry->ca_store);
|
||||
for (i = ca_index; i < sk_X509_OBJECT_num(objs); i++) {
|
||||
|
||||
cert = X509_OBJECT_get0_X509(sk_X509_OBJECT_value(objs, i));
|
||||
|
|
@ -3830,13 +3865,16 @@ static int cli_io_handler_show_cafile_detail(struct appctx *appctx)
|
|||
}
|
||||
|
||||
end:
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
free_trash_chunk(out);
|
||||
return 1; /* end, don't come back */
|
||||
|
||||
end_no_putchk:
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
free_trash_chunk(out);
|
||||
return 1;
|
||||
yield:
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
/* save the current state */
|
||||
ctx->ca_index = i;
|
||||
free_trash_chunk(out);
|
||||
|
|
@ -3939,9 +3977,10 @@ static int get_certificate_count(struct cafile_entry *cafile_entry)
|
|||
STACK_OF(X509_OBJECT) *objs;
|
||||
|
||||
if (cafile_entry && cafile_entry->ca_store) {
|
||||
objs = X509_STORE_get0_objects(cafile_entry->ca_store);
|
||||
objs = X509_STORE_getX_objects(cafile_entry->ca_store);
|
||||
if (objs)
|
||||
cert_count = sk_X509_OBJECT_num(objs);
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
}
|
||||
return cert_count;
|
||||
}
|
||||
|
|
@ -4471,7 +4510,7 @@ static int cli_io_handler_show_crlfile_detail(struct appctx *appctx)
|
|||
struct buffer *out = alloc_trash_chunk();
|
||||
int i;
|
||||
X509_CRL *crl;
|
||||
STACK_OF(X509_OBJECT) *objs;
|
||||
STACK_OF(X509_OBJECT) *objs = NULL;
|
||||
int retval = 0;
|
||||
int index = ctx->index;
|
||||
|
||||
|
|
@ -4496,7 +4535,7 @@ static int cli_io_handler_show_crlfile_detail(struct appctx *appctx)
|
|||
if (!cafile_entry->ca_store)
|
||||
goto end;
|
||||
|
||||
objs = X509_STORE_get0_objects(cafile_entry->ca_store);
|
||||
objs = X509_STORE_getX_objects(cafile_entry->ca_store);
|
||||
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
||||
crl = X509_OBJECT_get0_X509_CRL(sk_X509_OBJECT_value(objs, i));
|
||||
if (!crl)
|
||||
|
|
@ -4519,9 +4558,11 @@ end:
|
|||
goto yield;
|
||||
|
||||
end_no_putchk:
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
free_trash_chunk(out);
|
||||
return 1;
|
||||
yield:
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
free_trash_chunk(out);
|
||||
return 0; /* should come back */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,9 @@ struct global_ssl global_ssl = {
|
|||
#endif
|
||||
#ifdef HAVE_ACME
|
||||
.acme_scheduler = 1,
|
||||
#endif
|
||||
#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
|
||||
.certificate_compression = 1,
|
||||
#endif
|
||||
.renegotiate = SSL_RENEGOTIATE_DFLT,
|
||||
.passphrase_cmd = NULL,
|
||||
|
|
@ -627,7 +630,7 @@ static int ssl_set_cert_crl_file(X509_STORE *store_ctx, char *path)
|
|||
if (store_ctx && store) {
|
||||
int i;
|
||||
X509_OBJECT *obj;
|
||||
STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store);
|
||||
STACK_OF(X509_OBJECT) *objs = X509_STORE_getX_objects(store);
|
||||
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
||||
obj = sk_X509_OBJECT_value(objs, i);
|
||||
switch (X509_OBJECT_get_type(obj)) {
|
||||
|
|
@ -641,6 +644,7 @@ static int ssl_set_cert_crl_file(X509_STORE *store_ctx, char *path)
|
|||
break;
|
||||
}
|
||||
}
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -684,7 +688,7 @@ static STACK_OF(X509_NAME)* ssl_get_client_ca_file(char *path)
|
|||
|
||||
skn = sk_X509_NAME_new_null();
|
||||
/* take x509 from cafile_tree */
|
||||
objs = X509_STORE_get0_objects(ca_e->ca_store);
|
||||
objs = X509_STORE_getX_objects(ca_e->ca_store);
|
||||
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
||||
x = X509_OBJECT_get0_X509(sk_X509_OBJECT_value(objs, i));
|
||||
if (!x)
|
||||
|
|
@ -720,6 +724,7 @@ static STACK_OF(X509_NAME)* ssl_get_client_ca_file(char *path)
|
|||
ca_name->xname = xn;
|
||||
eb64_insert(&ca_name_tree, &ca_name->node);
|
||||
}
|
||||
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
|
||||
ca_e->ca_list = skn;
|
||||
/* remove temporary ca_name tree */
|
||||
node = eb64_first(&ca_name_tree);
|
||||
|
|
@ -796,16 +801,16 @@ static struct eb_root *sh_ssl_sess_tree; /* ssl shared session tree */
|
|||
/* Dedicated callback functions for heartbeat and clienthello.
|
||||
*/
|
||||
#ifdef TLS1_RT_HEARTBEAT
|
||||
static void ssl_sock_parse_heartbeat(struct connection *conn, int write_p, int version,
|
||||
static void ssl_sock_parse_heartbeat(int write_p, int version,
|
||||
int content_type, const void *buf, size_t len,
|
||||
SSL *ssl);
|
||||
#endif
|
||||
static void ssl_sock_parse_clienthello(struct connection *conn, int write_p, int version,
|
||||
static void ssl_sock_parse_clienthello(int write_p, int version,
|
||||
int content_type, const void *buf, size_t len,
|
||||
SSL *ssl);
|
||||
|
||||
#ifdef HAVE_SSL_KEYLOG
|
||||
static void ssl_init_keylog(struct connection *conn, int write_p, int version,
|
||||
static void ssl_init_keylog(int write_p, int version,
|
||||
int content_type, const void *buf, size_t len,
|
||||
SSL *ssl);
|
||||
#endif
|
||||
|
|
@ -1796,18 +1801,23 @@ int ssl_sock_bind_verifycbk(int ok, X509_STORE_CTX *x_store)
|
|||
}
|
||||
|
||||
#ifdef TLS1_RT_HEARTBEAT
|
||||
static void ssl_sock_parse_heartbeat(struct connection *conn, int write_p, int version,
|
||||
static void ssl_sock_parse_heartbeat(int write_p, int version,
|
||||
int content_type, const void *buf, size_t len,
|
||||
SSL *ssl)
|
||||
{
|
||||
/* test heartbeat received (write_p is set to 0
|
||||
for a received record) */
|
||||
if ((content_type == TLS1_RT_HEARTBEAT) && (write_p == 0)) {
|
||||
struct ssl_sock_ctx *ctx = __conn_get_ssl_sock_ctx(conn);
|
||||
struct connection *conn = ssl_sock_get_conn(ssl, NULL);
|
||||
struct ssl_sock_ctx *ctx = NULL;
|
||||
const unsigned char *p = buf;
|
||||
unsigned int payload;
|
||||
|
||||
ctx->xprt_st |= SSL_SOCK_RECV_HEARTBEAT;
|
||||
/* <conn> may be NULL in QUIC context */
|
||||
if (conn) {
|
||||
ctx = __conn_get_ssl_sock_ctx(conn);
|
||||
ctx->xprt_st |= SSL_SOCK_RECV_HEARTBEAT;
|
||||
}
|
||||
|
||||
/* Check if this is a CVE-2014-0160 exploitation attempt. */
|
||||
if (*p != TLS1_HB_REQUEST)
|
||||
|
|
@ -1838,7 +1848,7 @@ static void ssl_sock_parse_heartbeat(struct connection *conn, int write_p, int v
|
|||
}
|
||||
#endif
|
||||
|
||||
static void ssl_sock_parse_clienthello(struct connection *conn, int write_p, int version,
|
||||
static void ssl_sock_parse_clienthello(int write_p, int version,
|
||||
int content_type, const void *buf, size_t len,
|
||||
SSL *ssl)
|
||||
{
|
||||
|
|
@ -2132,7 +2142,7 @@ static void ssl_sock_parse_clienthello(struct connection *conn, int write_p, int
|
|||
|
||||
|
||||
#ifdef HAVE_SSL_KEYLOG
|
||||
static void ssl_init_keylog(struct connection *conn, int write_p, int version,
|
||||
static void ssl_init_keylog(int write_p, int version,
|
||||
int content_type, const void *buf, size_t len,
|
||||
SSL *ssl)
|
||||
{
|
||||
|
|
@ -2155,20 +2165,13 @@ static void ssl_init_keylog(struct connection *conn, int write_p, int version,
|
|||
/* Callback is called for ssl protocol analyse */
|
||||
static __maybe_unused void ssl_sock_msgcbk(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)
|
||||
{
|
||||
struct connection *conn = ssl_sock_get_conn(ssl, NULL);
|
||||
struct ssl_sock_msg_callback *cbk;
|
||||
|
||||
/* The connection be NULL only for QUIC which does not free its SSL object
|
||||
* as this done for TCP.
|
||||
*/
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
/* Try to call all callback functions that were registered by using
|
||||
* ssl_sock_register_msg_callback().
|
||||
*/
|
||||
list_for_each_entry(cbk, &ssl_sock_msg_callbacks, list) {
|
||||
cbk->func(conn, write_p, version, content_type, buf, len, ssl);
|
||||
cbk->func(write_p, version, content_type, buf, len, ssl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3813,6 +3816,8 @@ int ssl_sock_passwd_cb(char *buf, int size, int rwflag, void *userdata)
|
|||
if (!data || data->passphrase_idx == -1)
|
||||
return -1;
|
||||
|
||||
data->callback_called = 1;
|
||||
|
||||
ckch_data = data->ckch_data;
|
||||
|
||||
if (ckch_data)
|
||||
|
|
@ -3832,13 +3837,16 @@ int ssl_sock_passwd_cb(char *buf, int size, int rwflag, void *userdata)
|
|||
global_ssl.passphrase_cmd[1] = strdup(data->path);
|
||||
|
||||
if (!global_ssl.passphrase_cmd[1]) {
|
||||
data->passphrase_idx = -1;
|
||||
ha_alert("ssl_sock_passwd_cb: allocation failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!passphrase_cache)
|
||||
if (ssl_sock_create_passphrase_cache())
|
||||
if (ssl_sock_create_passphrase_cache()) {
|
||||
data->passphrase_idx = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Try all the already known passphrases first. */
|
||||
if (data->passphrase_idx < passphrase_idx) {
|
||||
|
|
@ -4074,6 +4082,11 @@ ssl_sock_initial_ctx(struct bind_conf *bind_conf)
|
|||
options |= SSL_OP_NO_RENEGOTIATION;
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
|
||||
if (global_ssl.certificate_compression == 0)
|
||||
options |= SSL_OP_NO_RX_CERTIFICATE_COMPRESSION | SSL_OP_NO_TX_CERTIFICATE_COMPRESSION;
|
||||
#endif
|
||||
|
||||
SSL_CTX_set_options(ctx, options);
|
||||
|
||||
#ifdef SSL_MODE_ASYNC
|
||||
|
|
@ -5127,6 +5140,11 @@ static int ssl_sock_prepare_srv_ssl_ctx(const struct server *srv, SSL_CTX *ctx)
|
|||
options &= ~SSL_OP_NO_RENEGOTIATION;
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
|
||||
if (global_ssl.certificate_compression == 0)
|
||||
options |= SSL_OP_NO_RX_CERTIFICATE_COMPRESSION | SSL_OP_NO_TX_CERTIFICATE_COMPRESSION;
|
||||
#endif
|
||||
|
||||
SSL_CTX_set_options(ctx, options);
|
||||
|
||||
#ifdef SSL_MODE_ASYNC
|
||||
|
|
@ -8536,6 +8554,7 @@ static void ssl_register_build_options()
|
|||
#if defined(USE_OPENSSL) && (HA_OPENSSL_VERSION_NUMBER < 0x3000000fL)
|
||||
memprintf(&ptr, "%s\nSSL library FIPS mode : %s", ptr, FIPS_mode() ? "yes" : "no");
|
||||
#endif
|
||||
memprintf(&ptr, "%s\nSSL library default verify directory : %s", ptr, ha_default_cert_dir());
|
||||
memprintf(&ptr, "%s\nSSL library supports :", ptr);
|
||||
for (i = CONF_TLSV_MIN; i <= CONF_TLSV_MAX; i++)
|
||||
if (methodVersions[i].option)
|
||||
|
|
|
|||
|
|
@ -5968,7 +5968,9 @@ static void stkt_late_init(void)
|
|||
f = find_sample_fetch("src", strlen("src"));
|
||||
if (f)
|
||||
smp_fetch_src = f->process;
|
||||
stkt_create_stk_ctr_pool();
|
||||
|
||||
if (stkt_create_stk_ctr_pool() & (ERR_ABORT | ERR_FATAL))
|
||||
exit(1); // error already reported by the function
|
||||
|
||||
for (i = 0; i < CONFIG_HAP_TBL_BUCKETS; i++) {
|
||||
MT_LIST_INIT(&per_bucket[i].toadd_tables);
|
||||
|
|
|
|||
|
|
@ -970,6 +970,12 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type,
|
|||
hdr->namelen = 0;
|
||||
hdr->len = len;
|
||||
hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
|
||||
if (!hdr->pool) {
|
||||
memprintf(err, "parsing [%s:%d] : out of memory", file, line);
|
||||
free(hdr);
|
||||
release_sample_expr(expr);
|
||||
return -1;
|
||||
}
|
||||
hdr->index = curpx->nb_req_cap++;
|
||||
|
||||
curpx->req_cap = hdr;
|
||||
|
|
|
|||
|
|
@ -4943,6 +4943,35 @@ int proxy_parse_mysql_check_opt(char **args, int cur_arg, struct proxy *curpx, c
|
|||
"01" /* COM_QUIT command */
|
||||
};
|
||||
|
||||
/* MySQL >=8.0 client Authentication packet with CLIENT_PLUGIN_AUTH capability.
|
||||
* MySQL 8.0 changed the default authentication plugin from mysql_native_password
|
||||
* to caching_sha2_password. By setting CLIENT_PLUGIN_AUTH and specifying
|
||||
* mysql_native_password as the auth plugin, we can still perform health checks
|
||||
* against MySQL 8.x servers when the health check user is configured with
|
||||
* mysql_native_password authentication.
|
||||
*
|
||||
* Client capabilities: 0x00088200 (little-endian: 00820800)
|
||||
* - CLIENT_PROTOCOL_41 (0x00000200)
|
||||
* - CLIENT_SECURE_CONNECTION (0x00008000)
|
||||
* - CLIENT_PLUGIN_AUTH (0x00080000)
|
||||
*/
|
||||
static char mysql80_rsname[] = "*mysql80-check";
|
||||
static char mysql80_req[] = {
|
||||
"%[var(check.header),hex]" /* 3 bytes for the packet length and 1 byte for the sequence ID */
|
||||
"00820800" /* client capabilities with CLIENT_PLUGIN_AUTH */
|
||||
"00800001" /* max packet */
|
||||
"21" /* character set (UTF-8) */
|
||||
"000000000000000000000000" /* 23 bytes, all zeroes */
|
||||
"0000000000000000000000"
|
||||
"%[var(check.username),hex]00" /* the username */
|
||||
"00" /* auth response length (0 = no password) */
|
||||
"6d7973716c5f6e61746976655f" /* auth plugin name: "mysql_native_password\0" */
|
||||
"70617373776f726400"
|
||||
"010000" /* packet length */
|
||||
"00" /* sequence ID */
|
||||
"01" /* COM_QUIT command */
|
||||
};
|
||||
|
||||
struct tcpcheck_ruleset *rs = NULL;
|
||||
struct tcpcheck_rules *rules = &curpx->tcpcheck_rules;
|
||||
struct tcpcheck_rule *chk;
|
||||
|
|
@ -4999,8 +5028,14 @@ int proxy_parse_mysql_check_opt(char **args, int cur_arg, struct proxy *curpx, c
|
|||
mysql_req = mysql40_req;
|
||||
mysql_rsname = mysql40_rsname;
|
||||
}
|
||||
else if (strcmp(args[cur_arg+2], "post-80") == 0) {
|
||||
/* post-80: CLIENT_PLUGIN_AUTH + mysql_native_password (22 bytes) */
|
||||
packetlen = userlen + 7 + 27 + 22;
|
||||
mysql_req = mysql80_req;
|
||||
mysql_rsname = mysql80_rsname;
|
||||
}
|
||||
else {
|
||||
ha_alert("parsing [%s:%d] : keyword '%s' only supports 'post-41' and 'pre-41' (got '%s').\n",
|
||||
ha_alert("parsing [%s:%d] : keyword '%s' only supports 'post-41', 'pre-41' and 'post-80' (got '%s').\n",
|
||||
file, line, args[cur_arg], args[cur_arg+2]);
|
||||
goto error;
|
||||
}
|
||||
|
|
|
|||
14
src/thread.c
14
src/thread.c
|
|
@ -1394,6 +1394,12 @@ int thread_map_to_groups()
|
|||
for (g = 0; g < global.nbtgroups; g++) {
|
||||
if (!ha_tgroup_info[g].count)
|
||||
ug++;
|
||||
else {
|
||||
if (ha_tgroup_info[g].count > global.maxthrpertgroup) {
|
||||
ha_alert("thread-group %d assigned too many threads (%d, max=%d)\n", g, ha_tgroup_info[g].count, global.maxthrpertgroup);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ha_tgroup_info[g].tgid_bit = 1UL << g;
|
||||
}
|
||||
|
||||
|
|
@ -1641,9 +1647,6 @@ void thread_detect_count(void)
|
|||
if (global.nbtgroups)
|
||||
grp_min = grp_max = global.nbtgroups;
|
||||
|
||||
if (!global.maxthrpertgroup)
|
||||
global.maxthrpertgroup = MAX_THREADS_PER_GROUP;
|
||||
|
||||
#if defined(USE_THREAD)
|
||||
/* Adjust to boot settings if not forced */
|
||||
if (thr_min <= thread_cpus_enabled_at_boot && thread_cpus_enabled_at_boot < thr_max)
|
||||
|
|
@ -2138,11 +2141,6 @@ static int cfg_parse_thread_group(char **args, int section_type, struct proxy *c
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (ha_tgroup_info[tgroup-1].count > global.maxthrpertgroup) {
|
||||
memprintf(err, "'%s %ld' assigned too many threads (%d, max=%d)", args[0], tgroup, tot, global.maxthrpertgroup);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
13
src/tools.c
13
src/tools.c
|
|
@ -987,6 +987,11 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
|
|||
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 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
|
|||
((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 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
|
|||
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 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
|
|||
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 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
|
|||
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 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
|
|||
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 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
|
|||
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 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
|
|||
}
|
||||
|
||||
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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue