MINOR: tcp-act: define optional arg name for attach-srv

Add an optional argument 'name' for attach-srv rule. This contains an
expression which will be used as an identifier inside the server idle
pool after reversal. To match this connection for a future transfer
through the server, the SNI server parameter must match this name. If no
name is defined, match will only occur with an empty SNI value.

For the moment, only the parsing step is implemented. An extra check is
added to ensure that the reverse server uses SSL with a SNI. Indeed, if
name is defined but server does not uses a SNI, connections will never
be selected on reused after reversal due to a hash mismatch.
This commit is contained in:
Amaury Denoyelle 2023-07-31 16:21:00 +02:00
parent f0bff29473
commit 0b3758e18f
3 changed files with 38 additions and 2 deletions

View File

@ -13825,7 +13825,7 @@ tcp-request session <action> [{if | unless} <condition>]
The first keyword is the rule's action. Several types of actions are
supported:
- accept
- attach-srv <srv>
- attach-srv <srv> [name <expr>]
- reject
- sc-add-gpc(<idx>,<sc-id>) { <int> | <expr> }
- sc-inc-gpc(<idx>,<sc-id>)
@ -13894,13 +13894,19 @@ tcp-request session accept [ { if | unless } <condition> ]
This is used to accept the connection. No further "tcp-request session"
rules are evaluated.
tcp-request session attach-srv <srv>
tcp-request session attach-srv <srv> [name <expr>]
This is used to intercept the connection after proper HTTP/2 establishment.
The connection is reversed to the backend side and inserted into the idle
pool of <srv> server. This is useful for reverse server with '@reverse'
address.
An extra parameter <expr> can be specified. Its value is interpreted as a
sample expression to name the connection inside the server idle pool. When
routing an outgoing request through this server, this name will be matched
against the 'sni' parameter of the server line. Otherwise, the connection
will have no name and will only match requests without SNI.
This rule is only valid for frontend in HTTP mode. Also all listeners must
not require a protocol different from HTTP/2.

View File

@ -188,6 +188,7 @@ struct act_rule {
struct {
char *srvname; /* server name from config parsing. */
struct server *srv; /* target server to attach the connection */
struct sample_expr *name; /* used to differentiate idle connections */
} attach_srv; /* 'attach-srv' rule */
struct {
void *p[4];

View File

@ -393,6 +393,7 @@ static enum act_return tcp_action_set_tos(struct act_rule *rule, struct proxy *p
static void release_attach_srv_action(struct act_rule *rule)
{
ha_free(&rule->arg.attach_srv.srvname);
release_sample_expr(rule->arg.attach_srv.name);
}
/*
@ -454,6 +455,12 @@ static int tcp_check_attach_srv(struct act_rule *rule, struct proxy *px, char **
return 0;
}
if ((rule->arg.attach_srv.name && (!srv->use_ssl || !srv->sni_expr)) ||
(!rule->arg.attach_srv.name && srv->use_ssl && srv->sni_expr)) {
memprintf(err, "attach-srv rule: connection will never be used; either specify name argument in conjonction with defined SSL SNI on targetted server or none of these");
return 0;
}
rule->arg.attach_srv.srv = srv;
return 1;
@ -463,12 +470,14 @@ static enum act_parse_ret tcp_parse_attach_srv(const char **args, int *cur_arg,
struct act_rule *rule, char **err)
{
char *srvname;
struct sample_expr *expr;
rule->action = ACT_CUSTOM;
rule->action_ptr = tcp_action_attach_srv;
rule->release_ptr = release_attach_srv_action;
rule->check_ptr = tcp_check_attach_srv;
rule->arg.attach_srv.srvname = NULL;
rule->arg.attach_srv.name = NULL;
srvname = my_strndup(args[*cur_arg], strlen(args[*cur_arg]));
if (!srvname)
@ -477,10 +486,30 @@ static enum act_parse_ret tcp_parse_attach_srv(const char **args, int *cur_arg,
++(*cur_arg);
while (args[*cur_arg] && args[*cur_arg][0] != '\0') {
if (strcmp(args[*cur_arg], "name") == 0) {
++(*cur_arg);
expr = sample_parse_expr((char **)args, cur_arg, px->conf.args.file, px->conf.args.line,
err, &px->conf.args, NULL);
if (!expr)
return ACT_RET_PRS_ERR;
rule->arg.attach_srv.name = expr;
rule->release_ptr = release_attach_srv_action;
++(*cur_arg);
}
else {
memprintf(err, "Unknown argument.");
return ACT_RET_PRS_ERR;
}
}
return ACT_RET_PRS_OK;
err:
ha_free(&rule->arg.attach_srv.srvname);
release_sample_expr(rule->arg.attach_srv.name);
return ACT_RET_PRS_ERR;
}