]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: rules/acl: Parse TCP/HTTP rules and acls defined in defaults sections
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 13 Oct 2021 13:40:15 +0000 (15:40 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 15 Oct 2021 12:12:19 +0000 (14:12 +0200)
TCP and HTTP rules can now be defined in defaults sections, but only those
with a name. Because these rules may use conditions based on ACLs, ACLs can
also be defined in defaults sections.

However there are some limitations:

  * A defaults section defining TCP/HTTP rules cannot be used by a defaults
    section
  * A defaults section defining TCP/HTTP rules cannot be used bu a listen
    section
  * A defaults sections defining TCP/HTTP rules cannot be used by frontends
    and backends at the same time
  * A defaults sections defining 'tcp-request connection' or 'tcp-request
    session' rules cannot be used by backends
  * A defaults sections defining 'tcp-response content' rules cannot be used
    by frontends

The TCP request/response inspect-delay of a proxy is now inherited from the
defaults section it uses. For now, these rules are only parsed. No evaluation is
performed.

src/cfgparse-listen.c
src/cfgparse.c
src/proxy.c
src/tcp_rules.c

index d079ecf40b72d7965a1a4e1bfb7213212211b141..9dbf7ed980f179cfb4aff6b1269a15ee592d0ad4 100644 (file)
@@ -333,6 +333,70 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                        goto out;
                }
 
+               if (curr_defproxy && (!LIST_ISEMPTY(&curr_defproxy->http_req_rules)        ||
+                                     !LIST_ISEMPTY(&curr_defproxy->http_res_rules)        ||
+                                     !LIST_ISEMPTY(&curr_defproxy->http_after_res_rules)  ||
+                                     !LIST_ISEMPTY(&curr_defproxy->tcp_req.l4_rules)      ||
+                                     !LIST_ISEMPTY(&curr_defproxy->tcp_req.l5_rules)      ||
+                                     !LIST_ISEMPTY(&curr_defproxy->tcp_req.inspect_rules) ||
+                                     !LIST_ISEMPTY(&curr_defproxy->tcp_rep.inspect_rules))) {
+                       /* If the current default proxy defines TCP/HTTP rules, the
+                        * current proxy will keep a reference on it. But some sanity
+                        * checks are performed first:
+                        *
+                        * - It cannot be used to init a defaults section
+                        * - It cannot be used to init a listen section
+                        * - It cannot be used to init backend and frontend sections at
+                        *   same time. It can be used to init several sections of the
+                        *   same type only.
+                        * - It cannot define L4/L5 TCP rules if it is used to init
+                        *   backend sections.
+                        * - It cannot define 'tcp-response content' rules if it
+                        *   is used to init frontend sections.
+                        *
+                        * If no error is found, refcount of the default proxy is incremented.
+                        */
+
+                       /* Note: Add tcpcheck_rules too if unresolve args become allowed in defaults section */
+                       if (rc & PR_CAP_DEF) {
+                               ha_alert("parsing [%s:%d]: a defaults section cannot inherit from a defaults section defining TCP/HTTP rules (defaults section at %s:%d).\n",
+                                        file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
+                               err_code |= ERR_ALERT | ERR_ABORT;
+                       }
+                       else if ((rc & PR_CAP_LISTEN) == PR_CAP_LISTEN) {
+                               ha_alert("parsing [%s:%d]: a listen section cannot inherit from a defaults section defining TCP/HTTP rules.\n",
+                                        file, linenum);
+                               err_code |= ERR_ALERT | ERR_ABORT;
+                       }
+                       else {
+                               char defcap = (curr_defproxy->cap & PR_CAP_LISTEN);
+
+                               if ((defcap == PR_CAP_BE || defcap == PR_CAP_FE) && (rc & PR_CAP_LISTEN) != defcap) {
+                                       ha_alert("parsing [%s:%d]: frontends and backends cannot inherit from the same defaults section"
+                                                " if it defines TCP/HTTP rules (defaults section at %s:%d).\n",
+                                                file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
+                                       err_code |= ERR_ALERT | ERR_ABORT;
+                               }
+                               else if (!(rc & PR_CAP_FE) && (!LIST_ISEMPTY(&curr_defproxy->tcp_req.l4_rules) ||
+                                                              !LIST_ISEMPTY(&curr_defproxy->tcp_req.l5_rules))) {
+                                       ha_alert("parsing [%s:%d]: a backend section cannot inherit from a defaults section defining"
+                                                " 'tcp-request connection' or 'tcp-request session' rules (defaults section at %s:%d).\n",
+                                                file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
+                                       err_code |= ERR_ALERT | ERR_ABORT;
+                               }
+                               else if (!(rc & PR_CAP_BE) && !LIST_ISEMPTY(&curr_defproxy->tcp_rep.inspect_rules)) {
+                                       ha_alert("parsing [%s:%d]: a frontend section cannot inherit from a defaults section defining"
+                                                " 'tcp-response content' rules (defaults section at %s:%d).\n",
+                                                file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
+                                       err_code |= ERR_ALERT | ERR_ABORT;
+                               }
+                               else {
+                                       curr_defproxy->cap = (curr_defproxy->cap & ~PR_CAP_LISTEN) | (rc & PR_CAP_LISTEN);
+                                       proxy_ref_defaults(curproxy, curr_defproxy);
+                               }
+                       }
+               }
+
                if (curr_defproxy && (curr_defproxy->tcpcheck_rules.flags & TCPCHK_RULES_PROTO_CHK) &&
                    (curproxy->cap & PR_CAP_LISTEN) == PR_CAP_BE) {
                        /* If the current default proxy defines tcpcheck rules, the
@@ -641,8 +705,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                err_code |= ERR_WARN;
        }
        else if (strcmp(args[0], "acl") == 0) {  /* add an ACL */
-               if (curproxy->cap & PR_CAP_DEF) {
-                       ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
+               if ((curproxy->cap & PR_CAP_DEF) && strlen(curproxy->id) == 0) {
+                       ha_alert("parsing [%s:%d] : '%s' not allowed in anonymous 'defaults' section.\n", file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
@@ -1212,8 +1276,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
        else if (strcmp(args[0], "http-request") == 0) {        /* request access control: allow/deny/auth */
                struct act_rule *rule;
 
-               if (curproxy->cap & PR_CAP_DEF) {
-                       ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
+               if ((curproxy->cap & PR_CAP_DEF) && strlen(curproxy->id) == 0) {
+                       ha_alert("parsing [%s:%d] : '%s' not allowed in anonymous 'defaults' section.\n", file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
@@ -1243,8 +1307,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
        else if (strcmp(args[0], "http-response") == 0) {       /* response access control */
                struct act_rule *rule;
 
-               if (curproxy->cap & PR_CAP_DEF) {
-                       ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
+               if ((curproxy->cap & PR_CAP_DEF) && strlen(curproxy->id) == 0) {
+                       ha_alert("parsing [%s:%d] : '%s' not allowed in anonymous 'defaults' section.\n", file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
@@ -1273,8 +1337,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
        else if (strcmp(args[0], "http-after-response") == 0) {
                struct act_rule *rule;
 
-               if (curproxy->cap & PR_CAP_DEF) {
-                       ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
+               if ((curproxy->cap & PR_CAP_DEF) && strlen(curproxy->id) == 0) {
+                       ha_alert("parsing [%s:%d] : '%s' not allowed in anonymous 'defaults' section.\n", file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
index 02ddd959d746d919d24915186809a5086d8ed1bc..00faeac8307df24bda4ce0f4e41f499e8f28ebea 100644 (file)
@@ -2520,6 +2520,15 @@ int check_config_validity()
                 */
                if (curproxy->defpx) {
                        if (!(curproxy->defpx->flags & PR_FL_READY)) {
+                               /* check validity for 'tcp-request' layer 4/5/6/7 rules */
+                               cfgerr += check_action_rules(&curproxy->defpx->tcp_req.l4_rules, curproxy->defpx, &err_code);
+                               cfgerr += check_action_rules(&curproxy->defpx->tcp_req.l5_rules, curproxy->defpx, &err_code);
+                               cfgerr += check_action_rules(&curproxy->defpx->tcp_req.inspect_rules, curproxy->defpx, &err_code);
+                               cfgerr += check_action_rules(&curproxy->defpx->tcp_rep.inspect_rules, curproxy->defpx, &err_code);
+                               cfgerr += check_action_rules(&curproxy->defpx->http_req_rules, curproxy->defpx, &err_code);
+                               cfgerr += check_action_rules(&curproxy->defpx->http_res_rules, curproxy->defpx, &err_code);
+                               cfgerr += check_action_rules(&curproxy->defpx->http_after_res_rules, curproxy->defpx, &err_code);
+
                                err = NULL;
                                i = smp_resolve_args(curproxy->defpx, &err);
                                cfgerr += i;
@@ -3612,8 +3621,8 @@ out_uri_auth_compat:
                        if (!curproxy->accept)
                                curproxy->accept = frontend_accept;
 
-                       if (curproxy->tcp_req.inspect_delay ||
-                           !LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules))
+                       if (!LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules) ||
+                           (curproxy->defpx && !LIST_ISEMPTY(&curproxy->defpx->tcp_req.inspect_rules)))
                                curproxy->fe_req_ana |= AN_REQ_INSPECT_FE;
 
                        if (curproxy->mode == PR_MODE_HTTP) {
@@ -3637,11 +3646,12 @@ out_uri_auth_compat:
                }
 
                if (curproxy->cap & PR_CAP_BE) {
-                       if (curproxy->tcp_req.inspect_delay ||
-                           !LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules))
+                       if (!LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules) ||
+                           (curproxy->defpx && !LIST_ISEMPTY(&curproxy->defpx->tcp_req.inspect_rules)))
                                curproxy->be_req_ana |= AN_REQ_INSPECT_BE;
 
-                       if (!LIST_ISEMPTY(&curproxy->tcp_rep.inspect_rules))
+                       if (!LIST_ISEMPTY(&curproxy->tcp_rep.inspect_rules) ||
+                           (curproxy->defpx && !LIST_ISEMPTY(&curproxy->defpx->tcp_rep.inspect_rules)))
                                 curproxy->be_rsp_ana |= AN_RES_INSPECT;
 
                        if (curproxy->mode == PR_MODE_HTTP) {
index c66aa8874da291cb584892e2af897216f6f9dd0d..27a917dfde76c47b925a60ff1522923fdf9ba5c0 100644 (file)
@@ -1576,6 +1576,8 @@ static int proxy_defproxy_cpy(struct proxy *curproxy, const struct proxy *defpro
        curproxy->except_xff_net = defproxy->except_xff_net;
        curproxy->except_xot_net = defproxy->except_xot_net;
        curproxy->retry_type = defproxy->retry_type;
+       curproxy->tcp_req.inspect_delay = defproxy->tcp_req.inspect_delay;
+       curproxy->tcp_rep.inspect_delay = defproxy->tcp_rep.inspect_delay;
 
        if (defproxy->fwdfor_hdr_len) {
                curproxy->fwdfor_hdr_len  = defproxy->fwdfor_hdr_len;
index 375da6befee0ce132c677e3188cd7c7fb8c3f5e7..5d97b25cbc06f2e2abf38e25ecc06f99d262ba4a 100644 (file)
@@ -574,8 +574,8 @@ static int tcp_parse_response_rule(char **args, int arg, int section_type,
                                    unsigned int where,
                                    const char *file, int line)
 {
-       if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
-               memprintf(err, "%s %s is only allowed in 'backend' sections",
+       if ((curpx == defpx && strlen(defpx->id) == 0) || !(curpx->cap & PR_CAP_BE)) {
+               memprintf(err, "%s %s is only allowed in 'backend' sections or 'defaults' section with a name",
                          args[0], args[1]);
                return -1;
        }
@@ -742,9 +742,9 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type,
                                   struct act_rule *rule, char **err,
                                   unsigned int where, const char *file, int line)
 {
-       if (curpx == defpx) {
-               memprintf(err, "%s %s is not allowed in 'defaults' sections",
-                         args[0], args[1]);
+       if (curpx == defpx && strlen(defpx->id) == 0) {
+               memprintf(err, "%s %s is not allowed in anonymous 'defaults' sections",
+                         args[0], args[1]);
                return -1;
        }
 
@@ -1031,8 +1031,8 @@ static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx,
        }
 
        if (strcmp(args[1], "inspect-delay") == 0) {
-               if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
-                       memprintf(err, "%s %s is only allowed in 'backend' sections",
+               if ((curpx == defpx && strlen(defpx->id) == 0) || !(curpx->cap & PR_CAP_BE)) {
+                       memprintf(err, "%s %s is only allowed in 'backend' sections or 'defaults' section with a name",
                                  args[0], args[1]);
                        return -1;
                }
@@ -1148,9 +1148,9 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
        }
 
        if (strcmp(args[1], "inspect-delay") == 0) {
-               if (curpx == defpx) {
-                       memprintf(err, "%s %s is not allowed in 'defaults' sections",
-                                 args[0], args[1]);
+               if (curpx == defpx && strlen(defpx->id) == 0) {
+                       memprintf(err, "%s %s is not allowed in anonymous 'defaults' sections",
+                                 args[0], args[1]);
                        return -1;
                }