]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tcp-act: define optional arg name for attach-srv
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 31 Jul 2023 14:21:00 +0000 (16:21 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 24 Aug 2023 13:28:38 +0000 (15:28 +0200)
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.

doc/configuration.txt
include/haproxy/action-t.h
src/tcp_act.c

index 9b5ab25cc667c55db9a1e2a67a325c88184d0e94..9626b4c995ad80ad2be9cb7d26c11cb87973f11b 100644 (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.
 
index 4237527bbf3215568fa8f66af9b9d975cdb65e87..7fafd612a4a68fcdaf76623f43431b0a4cfdf7e3 100644 (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];
index 9522e0f4991d23d746548ed4e6e26a0753d5de10..ab0649937dc6ea5885b340e79034a60c44bf7d9a 100644 (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;
 }