MAJOR: proxy: remove support for "dispatch" and "transparent" proxy keywords

These ones were deprecated in 3.3-dev2 with commits 5c15ba5eff ("MEDIUM:
proxy: mark the "dispatch" directive as deprecated") and e93f3ea3f8
("MEDIUM: proxy: deprecate the "transparent" and "option transparent"
directives"), and were planned for removal in 3.5. See also:

   https://github.com/orgs/haproxy/discussions/2921

as well as the wiki page about breaking changes.

They've lived their lives and always cause internal limitations
(exceptions between connecting to server or connecting to proxy), and
are even confusing to some extents (especially "transparent" which users
often get wrong).

This commit removes the ability to configure them, tests based on them
and all the doc related to them. The keywords remain detected by the
parser and indicate how to proceed instead.

It's likely that other deeper parts will be changed as well (e.g.
conn->target will no longer be of OBJ_TYPE_PROXY). This will be done
over the long term.
This commit is contained in:
Willy Tarreau 2026-06-26 10:36:55 +02:00
parent b12ef0aa44
commit be8159248f
7 changed files with 24 additions and 278 deletions

View file

@ -6160,7 +6160,6 @@ default-server X - X X
default_backend X X X -
description - X X X
disabled X X X X
dispatch (deprecated) - - X X
email-alert from X X X X
email-alert level X X X X
email-alert mailers X X X X
@ -6269,7 +6268,6 @@ option tcp-smart-accept (*) X X X -
option tcp-smart-connect (*) X - X X
option tcpka X X X X
option tcplog X X X -
option transparent (deprecated) (*) X - X X
option use-small-buffers (*) X - X X
persist rdp-cookie X - X X
quic-initial X (!) X X -
@ -6331,7 +6329,6 @@ timeout server X - X X
timeout server-fin X - X X
timeout tarpit X X X X
timeout tunnel X - X X
transparent (deprecated) X - X X
unique-id-format X X X X
unique-id-header X X X -
use_backend - X X -
@ -6746,7 +6743,7 @@ balance url_param <param> [check_post]
might be a URL parameter list. This is probably not a concern with SGML
type message bodies.
See also : "dispatch", "cookie", "transparent", "hash-type".
See also : "cookie", "hash-type".
bind [<address>]:<port_range> [, ...] [param*]
@ -7527,54 +7524,6 @@ disabled
See also : "enabled", "force-be-switch"
dispatch <address>:<port> (deprecated)
Set a default server address
May be used in the following contexts: tcp, http
May be used in sections : defaults | frontend | listen | backend
no | no | yes | yes
Arguments :
<address> is the IPv4 address of the default server. Alternatively, a
resolvable hostname is supported, but this name will be resolved
during start-up.
<ports> is a mandatory port specification. All connections will be sent
to this port, and it is not permitted to use port offsets as is
possible with normal servers.
The "dispatch" keyword designates a default server for use when no other
server can take the connection. In the past it was used to forward non
persistent connections to an auxiliary load balancer. Due to its simple
syntax, it has also been used for simple TCP relays. It is recommended not to
use it for more clarity, and to use the "server" directive instead.
This keyword has been deprecated in 3.3 and will be removed in 3.5 due to
some internal limitations (no support for SSL nor idle connections etc).
Using it will emit a warning that may be silenced by enabling directive
"expose-deprecated-directives" in the global section.
The correct way to proceed without this directive is to simply declare a
server with the same address and port. If the "dispatch" directive was
mixed with other servers, then these servers should be configured with a
weight of zero in order never to be elected by the load balancing algorithm.
Example:
backend deprecated_setup
dispatch 192.168.100.100:80 # external load balancer's address
server s1 192.168.100.1:80 cookie S1 check
server s2 192.168.100.2:80 cookie S2 check
backend modern_setup
server external_lb 192.168.100.100:80
server s1 192.168.100.1:80 cookie S1 check weight 0
server s2 192.168.100.2:80 cookie S2 check weight 0
See also : "server"
dynamic-cookie-key <string>
Set the dynamic cookie secret key for a backend.
@ -12137,46 +12086,6 @@ option tcplog [clf]
See also : "option httplog", and section 8 about logging.
option transparent (deprecated)
no option transparent (deprecated)
Enable client-side transparent proxying
May be used in the following contexts: tcp, http
May be used in sections : defaults | frontend | listen | backend
yes | no | yes | yes
Arguments : none
This option was introduced in order to provide layer 7 persistence to layer 3
load balancers. The idea is to use the OS's ability to redirect an incoming
connection for a remote address to a local process (here HAProxy), and let
this process know what address was initially requested. When this option is
used, sessions without cookies will be forwarded to the original destination
IP address of the incoming request (which should match that of another
equipment), while requests with cookies will still be forwarded to the
appropriate server.
Note that contrary to a common belief, this option does NOT make HAProxy
present the client's IP to the server when establishing the connection.
As of 3.3, this option is now deprecated because it used to suffer from a
number of internal technical limitations. Using it will emit a warning, which
can be avoided if really needed via the "expose-deprecated-directives" global
keyword.
The correct approach is to declare a server on address 0.0.0.0, which will
take care of connecting to the expected destination address. A server will
also properly handle idle connections to the target servers.
Example:
# option transparent ## before 3.3
server transparent 0.0.0.0
See also: the "usesrc" argument of the "source" keyword, and the
"transparent" option of the "bind" keyword.
option use-small-buffers [ queue | l7-retries | check ]*
Enable support for small buffers for the given categories.
@ -12605,9 +12514,9 @@ server <name> <address>[:[port]] [param*]
address as the one from the client connection. This is useful in
transparent proxy architectures where the client's connection is
intercepted and HAProxy must forward to the original destination
address. This is more or less what the "transparent" keyword does
except that with a server it's possible to limit concurrency and
to report statistics. Optionally, an address family prefix may be
address. This is more or less what the old "transparent" keyword
did except that servers do not have the keyword's limitations
(ssl, queues etc). Optionally, an address family prefix may be
used before the address to force the family regardless of the
address format, which can be useful to specify a path to a unix
socket with no slash ('/'). Currently supported prefixes are :
@ -15162,32 +15071,6 @@ timeout tunnel <timeout>
See also : "timeout client", "timeout client-fin", "timeout server".
transparent (deprecated)
Enable client-side transparent proxying
May be used in the following contexts: tcp, http
May be used in sections : defaults | frontend | listen | backend
yes | no | yes | yes
Arguments : none
This keyword was introduced in order to provide layer 7 persistence to layer
3 load balancers. The idea is to use the OS's ability to redirect an incoming
connection for a remote address to a local process (here HAProxy), and let
this process know what address was initially requested. When this option is
used, sessions without cookies will be forwarded to the original destination
IP address of the incoming request (which should match that of another
equipment), while requests with cookies will still be forwarded to the
appropriate server.
The "transparent" keyword is deprecated, use "option transparent" instead.
Note that contrary to a common belief, this option does NOT make HAProxy
present the client's IP to the server when establishing the connection.
See also: "option transparent"
unique-id-format <fmt>
Generate a unique ID for each request.

View file

@ -2148,8 +2148,7 @@ del backend <name>
There is additional restrictions which prevent backend removal. First, a
backend cannot be removed if it is explicitly referenced by config elements,
for example via a use_backend rule or in sample expressions. Some proxies
options are also incompatible with runtime deletion. Currently, this is the
case when deprecated dispatch or option transparent are used. Also, a backend
options are also incompatible with runtime deletion. Currently, a backend
cannot be removed if there is a stick-table declared in it. Finally, it is
impossible for now to remove a backend if QUIC servers were present in it.

View file

@ -79,7 +79,7 @@ enum PR_SRV_STATE_FILE {
/* bits for proxy->options */
#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
/* unused: 0x00000002 */
/* HTTP server-side reuse */
#define PR_O_REUSE_NEVR 0x00000000 /* never reuse a shared connection */
@ -90,7 +90,7 @@ enum PR_SRV_STATE_FILE {
#define PR_O_IDLE_CLOSE_RESP 0x00000010 /* avoid closing idle connections during a soft stop */
#define PR_O_PREF_LAST 0x00000020 /* prefer last server */
#define PR_O_DISPATCH 0x00000040 /* use dispatch mode */
/* unused: 0x00000040 */
#define PR_O_FORCED_ID 0x00000080 /* proxy's ID was forced in the configuration */
/* unused: 0x00000100 */
#define PR_O_IGNORE_PRB 0x00000200 /* ignore empty requests (aborts and timeouts) */
@ -327,7 +327,7 @@ struct proxy {
unsigned int maxconn; /* max # of active streams on the frontend */
int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
int options; /* PR_O_* */
int options2; /* PR_O2_* */
int options3; /* PR_O3_* */
unsigned int ck_opts; /* PR_CK_* (cookie options) */
@ -458,11 +458,10 @@ struct proxy {
unsigned int li_suspended; /* total number of listeners suspended (could be paused or unbound) */
/* warning: these structs are huge, keep them at the bottom */
struct sockaddr_storage dispatch_addr; /* the default address to connect to */
struct error_snapshot *invalid_req, *invalid_rep; /* captures of last errors */
/* used only during configuration parsing */
int no_options; /* PR_O_REDISP, PR_O_TRANSP, ... */
int no_options; /* PR_O_* */
int no_options2; /* PR_O2_* */
int no_options3; /* PR_O3_* */

View file

@ -1,50 +0,0 @@
varnishtest "Validate proper operation of the 'dispatch' mode"
feature ignore_unknown_macro
server s1 {
rxreq
txresp
} -start
server s2 {
rxreq
txresp
} -start
haproxy h1 -conf {
global
.if feature(THREAD)
thread-groups 1
.endif
# this is needed since 3.3, and this test will be removed in 3.5.
expose-deprecated-directives
defaults
log global
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
listen fe_tcp
bind "fd@${fe_tcp}"
mode tcp
dispatch ${s1_addr}:${s1_port}
listen fe_http
bind "fd@${fe_http}"
mode http
dispatch ${s2_addr}:${s2_port}
} -start
client c1 -connect ${h1_fe_tcp_sock} {
txreq -url "/"
rxresp
expect resp.status == 200
} -run
client c2 -connect ${h1_fe_http_sock} {
txreq -url "/"
rxresp
expect resp.status == 200
} -run

View file

@ -854,9 +854,6 @@ int assign_server(struct stream *s)
}
stream_set_srv_target(s, srv);
}
else if (s->be->options & (PR_O_DISPATCH | PR_O_TRANSP)) {
s->target = &s->be->obj_type;
}
else {
err = SRV_STATUS_NOSRV;
goto out;
@ -951,22 +948,6 @@ static int alloc_dst_address(struct sockaddr_storage **ss,
}
}
}
else if (s->be->options & PR_O_DISPATCH) {
if (!sockaddr_alloc(ss, NULL, 0))
return SRV_STATUS_INTERNAL;
/* connect to the defined dispatch addr */
**ss = s->be->dispatch_addr;
}
else if ((s->be->options & PR_O_TRANSP)) {
if (!sockaddr_alloc(ss, NULL, 0))
return SRV_STATUS_INTERNAL;
/* in transparent mode, use the original dest addr if no dispatch specified */
dst = sc_dst(s->scf);
if (dst && (dst->ss_family == AF_INET || dst->ss_family == AF_INET6))
**ss = *dst;
}
else {
/* no server and no LB algorithm ! */
return SRV_STATUS_INTERNAL;

View file

@ -2621,22 +2621,13 @@ stats_error_parsing:
goto out;
}
}
#ifdef USE_TPROXY
else if (strcmp(args[0], "transparent") == 0) {
/* enable transparent proxy connections */
curproxy->options |= PR_O_TRANSP;
if (alertif_too_many_args(0, file, linenum, args, &err_code))
goto out;
if (!deprecated_directives_allowed) {
ha_warning("parsing [%s:%d]: '%s' is deprecated in 3.3 and will be removed in 3.5. "
"The modern way to do the same is to create a server with address 0.0.0.0. It is "
"still possible to silence this warning by setting 'expose-deprecated-directives' "
"in the 'global' section, but do not wait to fix your configuration!\n",
file, linenum, args[0]);
err_code |= ERR_WARN;
}
ha_alert("parsing [%s:%d]: support for '%s' was removed in version 3.5. "
"The modern way to do the same is to create a server with address 0.0.0.0.\n",
file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
#endif
else if (strcmp(args[0], "maxconn") == 0) { /* maxconn */
if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], " Maybe you want 'fullconn' instead ?"))
err_code |= ERR_WARN;
@ -2683,43 +2674,13 @@ stats_error_parsing:
goto out;
}
else if (strcmp(args[0], "dispatch") == 0) { /* dispatch address */
struct sockaddr_storage *sk;
int port1, port2;
if (curproxy->cap & PR_CAP_DEF) {
ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
err_code |= ERR_WARN;
sk = str2sa_range(args[1], NULL, &port1, &port2, NULL, NULL, NULL,
&errmsg, NULL, NULL, NULL,
PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_STREAM | PA_O_XPRT | PA_O_CONNECT);
if (!sk) {
ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
if (alertif_too_many_args(1, file, linenum, args, &err_code))
goto out;
if (!deprecated_directives_allowed) {
ha_warning("parsing [%s:%d]: '%s' is deprecated in 3.3 and will be removed in 3.5. "
"The modern way to do the same is to create a server with the same address, and "
"possibly to assign any extra server a weight of zero if any:\n"
" server dispatch %s\n"
"Note that it is still possible to silence this warning by setting "
"'expose-deprecated-directives' in the 'global' section, but do not wait to fix "
"your configuration!\n",
file, linenum, args[0], args[1]);
err_code |= ERR_WARN;
}
curproxy->dispatch_addr = *sk;
curproxy->options |= PR_O_DISPATCH;
ha_alert("parsing [%s:%d]: support for '%s' was removed in version 3.5. "
"The modern way to do the same is to create a server with the same address, and "
"possibly to assign any extra server a weight of zero if any:\n"
" server dispatch %s\n",
file, linenum, args[0], args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
else if (strcmp(args[0], "balance") == 0) { /* set balancing with optional algorithm */
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))

View file

@ -117,11 +117,7 @@ const struct cfg_opt cfg_opts[] =
{ "nolinger", PR_O_TCP_NOLING, PR_CAP_FE | PR_CAP_BE, 0, 0 },
{ "persist", PR_O_PERSIST, PR_CAP_BE, 0, 0 },
{ "srvtcpka", PR_O_TCP_SRV_KA, PR_CAP_BE, 0, 0 },
#ifdef USE_TPROXY
{ "transparent", PR_O_TRANSP, PR_CAP_BE, 0, 0 },
#else
{ "transparent", 0, 0, 0, 0 },
#endif
{ "transparent", 0x305, 0, 0, 0 },
{ NULL, 0, 0, 0, 0 }
};
@ -1879,21 +1875,8 @@ int proxy_finalize(struct proxy *px, int *err_code)
}
if (px->cap & PR_CAP_BE) {
if (px->lbprm.algo & BE_LB_KIND) {
if (px->options & PR_O_TRANSP) {
ha_alert("%s '%s' cannot use both transparent and balance mode.\n",
proxy_type_str(px), px->id);
cfgerr++;
}
else if (px->options & PR_O_DISPATCH) {
ha_warning("dispatch address of %s '%s' will be ignored in balance mode.\n",
proxy_type_str(px), px->id);
*err_code |= ERR_WARN;
}
}
else if (!(px->options & (PR_O_TRANSP | PR_O_DISPATCH))) {
/* If no LB algo is set in a backend, and we're not in
* transparent mode, dispatch mode nor proxy mode, we
if (!(px->lbprm.algo & BE_LB_KIND)) {
/* If no LB algo is set in a backend, we
* want to use balance random by default.
*/
px->lbprm.algo &= ~BE_LB_ALGO;
@ -1901,11 +1884,6 @@ int proxy_finalize(struct proxy *px, int *err_code)
}
}
if (px->options & PR_O_DISPATCH)
px->options &= ~PR_O_TRANSP;
else if (px->options & PR_O_TRANSP)
px->options &= ~PR_O_DISPATCH;
if ((px->tcpcheck.flags & TCPCHK_FL_UNUSED_HTTP_RS)) {
ha_warning("%s '%s' uses http-check rules without 'option httpchk', so the rules are ignored.\n",
proxy_type_str(px), px->id);
@ -5041,11 +5019,6 @@ int be_check_for_deletion(const char *bename, struct proxy **pb, const char **pm
goto out;
}
if (be->options & (PR_O_DISPATCH|PR_O_TRANSP)) {
msg = "Deletion of backend with deprecated dispatch/transparent options is not supported.";
goto out;
}
if (be->table) {
msg = "Cannot remove a backend with stick-table.";
goto out;