MINOR: tcp-act: parse 'tcp-request attach-srv' session rule

Create a new tcp-request session rule 'attach-srv'.

The parsing handler is used to extract the server targetted with the
notation 'backend/server'. The server instance is stored in the act_rule
instance under the new union variant 'attach_srv'.

Extra checks are implemented in parsing to ensure attach-srv is only
used for proxy in HTTP mode and with listeners/server with no explicit
protocol reference or HTTP/2 only.

The action handler itself is really simple. It assigns the stored server
instance to the 'reverse' member of the connection instance. It will be
used in a future patch to implement passive reverse-connect.
This commit is contained in:
Amaury Denoyelle 2023-07-25 15:59:30 +02:00
parent 6e428dfaf2
commit 58cb76d7e1
4 changed files with 128 additions and 1 deletions

View File

@ -13825,6 +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>
- reject
- sc-add-gpc(<idx>,<sc-id>) { <int> | <expr> }
- sc-inc-gpc(<idx>,<sc-id>)
@ -13893,6 +13894,16 @@ 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>
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.
This rule is only valid for frontend in HTTP mode. Also all listeners must
not require a protocol different from HTTP/2.
tcp-request session reject [ { if | unless } <condition> ]
This is used to reject the connection. No further "tcp-request session" rules

View File

@ -185,6 +185,10 @@ struct act_rule {
struct sample_expr *expr;
} gpt;
struct track_ctr_prm trk_ctr;
struct {
char *srvname; /* server name from config parsing. */
struct server *srv; /* target server to attach the connection */
} attach_srv; /* 'attach-srv' rule */
struct {
void *p[4];
} act; /* generic pointers to be used by custom actions */

View File

@ -703,6 +703,15 @@ static inline int conn_is_reverse(const struct connection *conn)
return !!(conn->reverse.target);
}
/* Initialize <conn> as a reverse connection to <target>. */
static inline void conn_set_reverse(struct connection *conn, enum obj_type *target)
{
/* Ensure the correct target type is used depending on the connection side before reverse. */
BUG_ON(!conn_is_back(conn) && !objt_server(target));
conn->reverse.target = target;
}
#endif /* _HAPROXY_CONNECTION_H */
/*

View File

@ -32,13 +32,26 @@
#include <haproxy/global.h>
#include <haproxy/http_rules.h>
#include <haproxy/proto_tcp.h>
#include <haproxy/proxy-t.h>
#include <haproxy/proxy.h>
#include <haproxy/sample.h>
#include <haproxy/sc_strm.h>
#include <haproxy/server.h>
#include <haproxy/session.h>
#include <haproxy/tcp_rules.h>
#include <haproxy/tools.h>
static enum act_return tcp_action_attach_srv(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct server *srv = rule->arg.attach_srv.srv;
struct connection *conn = objt_conn(sess->origin);
if (!conn)
return ACT_RET_ABRT;
conn_set_reverse(conn, &srv->obj_type);
return ACT_RET_CONT;
}
/*
* Execute the "set-src" action. May be called from {tcp,http}request.
* It only changes the address and tries to preserve the original port. If the
@ -374,6 +387,14 @@ static enum act_return tcp_action_set_tos(struct act_rule *rule, struct proxy *p
}
#endif
/*
* Release the sample expr when releasing attach-srv action
*/
static void release_attach_srv_action(struct act_rule *rule)
{
ha_free(&rule->arg.attach_srv.srvname);
}
/*
* Release the sample expr when releasing a set src/dst action
*/
@ -382,6 +403,87 @@ static void release_set_src_dst_action(struct act_rule *rule)
release_sample_expr(rule->arg.expr);
}
static int tcp_check_attach_srv(struct act_rule *rule, struct proxy *px, char **err)
{
struct proxy *be = NULL;
struct server *srv = NULL;
struct bind_conf *bind_conf;
char *name = rule->arg.attach_srv.srvname;
struct ist be_name, sv_name;
if (px->mode != PR_MODE_HTTP) {
memprintf(err, "attach-srv rule requires HTTP proxy mode");
return 0;
}
list_for_each_entry(bind_conf, &px->conf.bind, by_fe) {
if ((bind_conf->mux_proto && !isteqi(bind_conf->mux_proto->token, ist("h2")))
#ifdef USE_OPENSSL
|| (bind_conf->ssl_conf.alpn_str && strcmp(bind_conf->ssl_conf.alpn_str, "\x02h2") != 0)
#endif
) {
memprintf(err, "attach-srv rule: incompatible with listener on %s:%d which uses protocol other than HTTP/2",
bind_conf->file, bind_conf->line);
return 0;
}
}
sv_name = ist(name);
be_name = istsplit(&sv_name, '/');
if (!istlen(sv_name)) {
memprintf(err, "attach-srv rule: invalid server name '%s'", name);
return 0;
}
if (!(be = proxy_be_by_name(ist0(be_name)))) {
memprintf(err, "attach-srv rule: no such backend '%s/%s'", ist0(be_name), ist0(sv_name));
return 0;
}
if (!(srv = server_find_by_name(be, ist0(sv_name)))) {
memprintf(err, "attach-srv rule: no such server '%s/%s'", ist0(be_name), ist0(sv_name));
return 0;
}
if ((srv->mux_proto && !isteqi(srv->mux_proto->token, ist("h2")))
#ifdef USE_OPENSSL
|| (srv->ssl_ctx.alpn_str && strcmp(srv->ssl_ctx.alpn_str, "\x02h2") != 0)
#endif
) {
memprintf(err, "attach-srv rule: incompatible with server '%s:%s' which uses protocol other than HTTP/2",
ist0(be_name), ist0(sv_name));
return 0;
}
rule->arg.attach_srv.srv = srv;
return 1;
}
static enum act_parse_ret tcp_parse_attach_srv(const char **args, int *cur_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
char *srvname;
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;
srvname = my_strndup(args[*cur_arg], strlen(args[*cur_arg]));
if (!srvname)
goto err;
rule->arg.attach_srv.srvname = srvname;
++(*cur_arg);
return ACT_RET_PRS_OK;
err:
ha_free(&rule->arg.attach_srv.srvname);
return ACT_RET_PRS_ERR;
}
/* parse "set-{src,dst}[-port]" action */
static enum act_parse_ret tcp_parse_set_src_dst(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
@ -551,6 +653,7 @@ static struct action_kw_list tcp_req_conn_actions = {ILH, {
INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_req_conn_actions);
static struct action_kw_list tcp_req_sess_actions = {ILH, {
{ "attach-srv" , tcp_parse_attach_srv },
{ "set-dst" , tcp_parse_set_src_dst },
{ "set-dst-port", tcp_parse_set_src_dst },
{ "set-mark", tcp_parse_set_mark },