[MEDIUM] add support for anonymous ACLs
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 }
diff --git a/doc/configuration.txt b/doc/configuration.txt
index ccb7e1c..4e6f631 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -6216,6 +6216,36 @@
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.
diff --git a/src/acl.c b/src/acl.c
index 007751d..c6c7484 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -963,16 +963,45 @@
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));
diff --git a/src/cfgparse.c b/src/cfgparse.c
index a57f1bf..4263f94 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -4733,42 +4733,36 @@
}
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: