diff --git a/doc/configuration.txt b/doc/configuration.txt index 9b5ab25cc..9626b4c99 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -13825,7 +13825,7 @@ tcp-request session [{if | unless} ] The first keyword is the rule's action. Several types of actions are supported: - accept - - attach-srv + - attach-srv [name ] - reject - sc-add-gpc(,) { | } - sc-inc-gpc(,) @@ -13894,13 +13894,19 @@ tcp-request session accept [ { if | unless } ] This is used to accept the connection. No further "tcp-request session" rules are evaluated. -tcp-request session attach-srv +tcp-request session attach-srv [name ] 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 server. This is useful for reverse server with '@reverse' address. + An extra parameter 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. diff --git a/include/haproxy/action-t.h b/include/haproxy/action-t.h index 4237527bb..7fafd612a 100644 --- a/include/haproxy/action-t.h +++ b/include/haproxy/action-t.h @@ -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]; diff --git a/src/tcp_act.c b/src/tcp_act.c index 9522e0f49..ab0649937 100644 --- a/src/tcp_act.c +++ b/src/tcp_act.c @@ -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; }