]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] acl: when possible, report the name and requirements of ACLs in warnings
authorWilly Tarreau <w@1wt.eu>
Sun, 27 Jul 2008 20:02:32 +0000 (22:02 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 3 Aug 2008 07:41:05 +0000 (09:41 +0200)
When an ACL is referenced at a wrong place (eg: response during request, layer7
during layer4), try to indicate precisely the name and requirements of this ACL.

Only the first faulty ACL is returned. A small change consisting in iterating
that way may improve reports :
   cap = ACL_USE_any_unexpected
   while ((acl=cond_find_require(cond, cap))) {
     warning()
     cap &= ~acl->requires;
   }

This will report the first ACL of each unsupported type. But doing so will
mangle the error reporting a lot, so we need to rework error reports first.

include/proto/acl.h
src/acl.c
src/cfgparse.c
src/proto_tcp.c

index ae64a5053f103bd026b3179c7f1c751fd4690af1..fffce481564641097669b423d6dafc711a61b609 100644 (file)
@@ -87,6 +87,11 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
  */
 int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, void *l7, int dir);
 
+/* Reports a pointer to the first ACL used in condition <cond> which requires
+ * at least one of the USE_FLAGS in <require>. Returns NULL if none matches.
+ */
+struct acl *cond_find_require(struct acl_cond *cond, unsigned int require);
+
 /* Return a pointer to the ACL <name> within the list starting at <head>, or
  * NULL if not found.
  */
index 30c30de6c1b9cbc209474c364d980974a830f1f8..ed41e91ed07f3fc269aa4f89105423d850bf9210 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -1096,6 +1096,30 @@ int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, v
 }
 
 
+/* Reports a pointer to the first ACL used in condition <cond> which requires
+ * at least one of the USE_FLAGS in <require>. Returns NULL if none matches.
+ * The construct is almost the same as for acl_exec_cond() since we're walking
+ * down the ACL tree as well. It is important that the tree is really walked
+ * through and never cached, because that way, this function can be used as a
+ * late check.
+ */
+struct acl *cond_find_require(struct acl_cond *cond, unsigned int require)
+{
+       struct acl_term_suite *suite;
+       struct acl_term *term;
+       struct acl *acl;
+
+       list_for_each_entry(suite, &cond->suites, list) {
+               list_for_each_entry(term, &suite->terms, list) {
+                       acl = term->acl;
+                       if (acl->requires & require)
+                               return acl;
+               }
+       }
+       return NULL;
+}
+
+
 /************************************************************************/
 /*             All supported keywords must be declared here.            */
 /************************************************************************/
index 1f1755ff9ff0955989494f29cd2272902bc0c4a8..09f63a40c7126761e8f9570bf08efeac3ce4ac7a 100644 (file)
@@ -1244,8 +1244,13 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
 
                cond->line = linenum;
                if (cond->requires & ACL_USE_RTR_ANY) {
-                       Warning("parsing [%s:%d] : switching rule involves some response-only criteria which will be ignored.\n",
-                               file, linenum);
+                       struct acl *acl;
+                       const char *name;
+
+                       acl = cond_find_require(cond, ACL_USE_RTR_ANY);
+                       name = acl ? acl->name : "(unknown)";
+                       Warning("parsing [%s:%d] : acl '%s' involves some response-only criteria which will be ignored.\n",
+                               file, linenum, name);
                }
 
                rule = (struct switching_rule *)calloc(1, sizeof(*rule));
index 3d93a34b108afe6f116e6e201efca576ad0632e5..cc96033c8d94d88f581c07855c04f1e8ac0586a7 100644 (file)
@@ -377,6 +377,7 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
 
        if (!strcmp(args[1], "content")) {
                int action;
+               int warn = 0;
                int pol = ACL_COND_NONE;
                struct acl_cond *cond;
                struct tcp_rule *rule;
@@ -410,17 +411,32 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
                if (pol != ACL_COND_NONE &&
                    (cond = parse_acl_cond((const char **)args+4, &curpx->acl, pol)) == NULL) {
                        retlen = snprintf(err, errlen,
-                                         "Error detected in %s '%s' while parsing '%s' condition",
+                                         "error detected in %s '%s' while parsing '%s' condition",
                                          proxy_type_str(curpx), curpx->id, args[3]);
                        return -1;
                }
 
+               // FIXME: how to set this ?
+               // cond->line = linenum;
+               if (cond->requires & (ACL_USE_RTR_ANY | ACL_USE_L7_ANY)) {
+                       struct acl *acl;
+                       const char *name;
+
+                       acl = cond_find_require(cond, ACL_USE_RTR_ANY|ACL_USE_L7_ANY);
+                       name = acl ? acl->name : "(unknown)";
+
+                       retlen = snprintf(err, errlen,
+                                         "acl '%s' involves some %s criteria which will be ignored.",
+                                         name,
+                                         (acl->requires & ACL_USE_RTR_ANY) ? "response-only" : "layer 7");
+                       warn++;
+               }
                rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
                rule->cond = cond;
                rule->action = action;
                LIST_INIT(&rule->list);
                LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
-               return 0;
+               return warn;
        }
 
        snprintf(err, errlen, "unknown argument '%s' after '%s' in %s '%s'",