]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] add support for anonymous ACLs
authorWilly Tarreau <w@1wt.eu>
Mon, 1 Feb 2010 12:05:50 +0000 (13:05 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 1 Feb 2010 12:05:50 +0000 (13:05 +0100)
Anonymous ACLs allow the declaration of rules which rely directly on
ACL expressions without passing via the declaration of an ACL. Example :

   With named ACLs :

        acl site_dead nbsrv(dynamic) lt 2
        acl site_dead nbsrv(static)  lt 2
        monitor fail  if site_dead

   With anonymous ACLs :

        monitor fail if { nbsrv(dynamic) lt 2 } || { nbsrv(static) lt 2 }

doc/configuration.txt
src/acl.c
src/cfgparse.c

index ccb7e1cc2abc7dbbf1fb007ce78afc8fc61ff951..4e6f63102aec095126fa0023ad47ee421e57fa49 100644 (file)
@@ -6216,6 +6216,36 @@ and to every request on the "img", "video", "download" and "ftp" hosts :
    use_backend static if host_static or host_www url_static
    use_backend www    if host_www
 
+It is also possible to form rules using "anonymous ACLs". Those are unnamed ACL
+expressions that are built on the fly without needing to be declared. They must
+be enclosed between braces, with a space before and after each brace (because
+the braces must be seen as independant words). Example :
+
+   The following rule :
+
+       acl missing_cl hdr_cnt(Content-length) eq 0
+       block if METH_POST missing_cl
+
+   Can also be written that way :
+
+       block if METH_POST { hdr_cnt(Content-length) eq 0 }
+
+It is generally not recommended to use this construct because it's a lot easier
+to leave errors in the configuration when written that way. However, for very
+simple rules matching only one source IP address for instance, it can make more
+sense to use them than to declare ACLs with random names. Another example of
+good use is the following :
+
+   With named ACLs :
+
+        acl site_dead nbsrv(dynamic) lt 2
+        acl site_dead nbsrv(static)  lt 2
+        monitor fail  if site_dead
+
+   With anonymous ACLs :
+
+        monitor fail if { nbsrv(dynamic) lt 2 } || { nbsrv(static) lt 2 }
+
 See section 4.2 for detailed help on the "block" and "use_backend" keywords.
 
 
index 007751de66182662fa15dc4664f141cad5a0dc63..c6c7484a3a272fc7f56dc93a2a9f2ede7c73202e 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -963,16 +963,45 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
                        continue;
                }
 
-               /* search for <word> in the known ACL names. If we do not find
-                * it, let's look for it in the default ACLs, and if found, add
-                * it to the list of ACLs of this proxy. This makes it possible
-                * to override them.
-                */
-               cur_acl = find_acl_by_name(word, known_acl);
-               if (cur_acl == NULL) {
-                       cur_acl = find_acl_default(word, known_acl);
-                       if (cur_acl == NULL)
+               if (strcmp(word, "{") == 0) {
+                       /* we may have a complete ACL expression between two braces,
+                        * find the last one.
+                        */
+                       int arg_end = arg + 1;
+                       const char **args_new;
+
+                       while (*args[arg_end] && strcmp(args[arg_end], "}") != 0)
+                               arg_end++;
+
+                       if (!*args[arg_end])
+                               goto out_free_suite;
+
+                       args_new = calloc(1, (arg_end - arg + 1) * sizeof(*args_new));
+                       if (!args_new)
                                goto out_free_suite;
+
+                       args_new[0] = ".noname";
+                       memcpy(args_new + 1, args + arg + 1, (arg_end - arg) * sizeof(*args_new));
+                       args_new[arg_end - arg] = "";
+                       cur_acl = parse_acl(args_new, known_acl);
+                       free(args_new);
+
+                       if (!cur_acl)
+                               goto out_free_suite;
+                       arg = arg_end;
+               }
+               else {
+                       /* search for <word> in the known ACL names. If we do not find
+                        * it, let's look for it in the default ACLs, and if found, add
+                        * it to the list of ACLs of this proxy. This makes it possible
+                        * to override them.
+                        */
+                       cur_acl = find_acl_by_name(word, known_acl);
+                       if (cur_acl == NULL) {
+                               cur_acl = find_acl_default(word, known_acl);
+                               if (cur_acl == NULL)
+                                       goto out_free_suite;
+                       }
                }
 
                cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term));
index a57f1bf9a056480b5aff29fd6b75862c37bec6ea..4263f943240dacd1fd7140100d852d015f27f388 100644 (file)
@@ -4733,42 +4733,36 @@ int check_config_validity()
                }
 
                if (curproxy->uri_auth && curproxy->uri_auth->userlist) {
-                       const char *uri_auth_compat_acl[3] = { ".internal-stats-auth-ok", "http_auth(.internal-stats-userlist)", ""};
-                       const char *uri_auth_compat_req[][4] = {
-                               { "allow", "if", ".internal-stats-auth-ok", ""},
-                               { "auth", "", "", ""},
-                               { 0 },
-                       };
+                       const char *uri_auth_compat_req[10];
                        struct req_acl_rule *req_acl;
-                       int i;
+                       int i = 0;
 
-                       if (parse_acl(uri_auth_compat_acl, &curproxy->acl) == NULL) {
-                               Alert("Error compiling internal auth-compat acl.\n");
-                               cfgerr++;
-                               goto out_uri_auth_compat;
-                       }
+                       /* build the ACL condition from scratch. We're relying on anonymous ACLs for that */
+                       uri_auth_compat_req[i++] = "auth";
 
                        if (curproxy->uri_auth->auth_realm) {
-                               uri_auth_compat_req[1][1] = "realm";
-                               uri_auth_compat_req[1][2] = curproxy->uri_auth->auth_realm;
-                       } else
-                               uri_auth_compat_req[1][1] = "";
+                               uri_auth_compat_req[i++] = "realm";
+                               uri_auth_compat_req[i++] = curproxy->uri_auth->auth_realm;
+                       }
 
-                       for (i = 0; *uri_auth_compat_req[i]; i++) {
-                               req_acl = parse_auth_cond(uri_auth_compat_req[i], "internal-stats-auth-compat", i, curproxy);
-                               if (!req_acl) {
-                                       cfgerr++;
-                                       break;
-                               }
+                       uri_auth_compat_req[i++] = "unless";
+                       uri_auth_compat_req[i++] = "{";
+                       uri_auth_compat_req[i++] = "http_auth(.internal-stats-userlist)";
+                       uri_auth_compat_req[i++] = "}";
+                       uri_auth_compat_req[i++] = "";
 
-                               LIST_ADDQ(&curproxy->uri_auth->req_acl, &req_acl->list);
+                       req_acl = parse_auth_cond(uri_auth_compat_req, "internal-stats-auth-compat", 0, curproxy);
+                       if (!req_acl) {
+                               cfgerr++;
+                               break;
                        }
 
+                       LIST_ADDQ(&curproxy->uri_auth->req_acl, &req_acl->list);
+
                        if (curproxy->uri_auth->auth_realm) {
                                free(curproxy->uri_auth->auth_realm);
                                curproxy->uri_auth->auth_realm = NULL;
                        }
-
                }
 out_uri_auth_compat: