[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 }
This commit is contained in:
Willy Tarreau 2010-02-01 13:05:50 +01:00
parent 711ad9eb27
commit 95fa4698f1
3 changed files with 88 additions and 35 deletions

View 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.

View File

@ -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));

View 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] = "";
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;
}
LIST_ADDQ(&curproxy->uri_auth->req_acl, &req_acl->list);
uri_auth_compat_req[i++] = "realm";
uri_auth_compat_req[i++] = curproxy->uri_auth->auth_realm;
}
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++] = "";
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: