MEDIUM: acl: report parsing errors to the caller

All parsing errors were known but impossible to return. Now by making use
of memprintf(), we're able to build meaningful error messages that the
caller can display.
This commit is contained in:
Willy Tarreau 2012-04-27 12:38:15 +02:00
parent 28376d62cb
commit b7451bb660
5 changed files with 229 additions and 93 deletions

View File

@ -59,7 +59,7 @@ struct acl_keyword *find_acl_kw(const char *kw);
* Right now, the only accepted syntax is : * Right now, the only accepted syntax is :
* <subject> [<value>...] * <subject> [<value>...]
*/ */
struct acl_expr *parse_acl_expr(const char **args); struct acl_expr *parse_acl_expr(const char **args, char **err);
/* Purge everything in the acl <acl>, then return <acl>. */ /* Purge everything in the acl <acl>, then return <acl>. */
struct acl *prune_acl(struct acl *acl); struct acl *prune_acl(struct acl *acl);
@ -70,7 +70,7 @@ struct acl *prune_acl(struct acl *acl);
* *
* args syntax: <aclname> <acl_expr> * args syntax: <aclname> <acl_expr>
*/ */
struct acl *parse_acl(const char **args, struct list *known_acl); struct acl *parse_acl(const char **args, struct list *known_acl, char **err);
/* Purge everything in the acl_cond <cond>, then return <cond>. */ /* Purge everything in the acl_cond <cond>, then return <cond>. */
struct acl_cond *prune_acl_cond(struct acl_cond *cond); struct acl_cond *prune_acl_cond(struct acl_cond *cond);
@ -79,15 +79,16 @@ struct acl_cond *prune_acl_cond(struct acl_cond *cond);
* known ACLs passed in <known_acl>. The new condition is returned (or NULL in * known ACLs passed in <known_acl>. The new condition is returned (or NULL in
* case of low memory). Supports multiple conditions separated by "or". * case of low memory). Supports multiple conditions separated by "or".
*/ */
struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol); struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol, char **err);
/* Builds an ACL condition starting at the if/unless keyword. The complete /* Builds an ACL condition starting at the if/unless keyword. The complete
* condition is returned. NULL is returned in case of error or if the first * condition is returned. NULL is returned in case of error or if the first
* word is neither "if" nor "unless". It automatically sets the file name and * word is neither "if" nor "unless". It automatically sets the file name and
* the line number in the condition for better error reporting, and adds the * the line number in the condition for better error reporting, and adds the
* ACL requirements to the proxy's acl_requires. * ACL requirements to the proxy's acl_requires. If <err> is not NULL, it will
* be set to an error message upon errors, that the caller will have to free.
*/ */
struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args); struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args, char **err);
/* Execute condition <cond> and return either ACL_PAT_FAIL, ACL_PAT_MISS or /* Execute condition <cond> and return either ACL_PAT_FAIL, ACL_PAT_MISS or
* ACL_PAT_PASS depending on the test results. This function only computes the * ACL_PAT_PASS depending on the test results. This function only computes the

185
src/acl.c
View File

@ -1224,11 +1224,14 @@ static int acl_read_patterns_from_file( struct acl_keyword *aclkw,
return ret; return ret;
} }
/* Parse an ACL expression starting at <args>[0], and return it. /* Parse an ACL expression starting at <args>[0], and return it. If <err> is
* not NULL, it will be filled with a pointer to an error message in case of
* error. This pointer must be freeable or NULL.
*
* Right now, the only accepted syntax is : * Right now, the only accepted syntax is :
* <subject> [<value>...] * <subject> [<value>...]
*/ */
struct acl_expr *parse_acl_expr(const char **args) struct acl_expr *parse_acl_expr(const char **args, char **err)
{ {
__label__ out_return, out_free_expr, out_free_pattern; __label__ out_return, out_free_expr, out_free_pattern;
struct acl_expr *expr; struct acl_expr *expr;
@ -1238,12 +1241,18 @@ struct acl_expr *parse_acl_expr(const char **args)
const char *arg; const char *arg;
aclkw = find_acl_kw(args[0]); aclkw = find_acl_kw(args[0]);
if (!aclkw || !aclkw->parse) if (!aclkw || !aclkw->parse) {
if (err)
memprintf(err, "unknown ACL keyword '%s'", *args);
goto out_return; goto out_return;
}
expr = (struct acl_expr *)calloc(1, sizeof(*expr)); expr = (struct acl_expr *)calloc(1, sizeof(*expr));
if (!expr) if (!expr) {
if (err)
memprintf(err, "out of memory when parsing ACL expression");
goto out_return; goto out_return;
}
expr->kw = aclkw; expr->kw = aclkw;
aclkw->use_cnt++; aclkw->use_cnt++;
@ -1259,8 +1268,11 @@ struct acl_expr *parse_acl_expr(const char **args)
/* there are 0 or more arguments in the form "subject(arg[,arg]*)" */ /* there are 0 or more arguments in the form "subject(arg[,arg]*)" */
arg++; arg++;
end = strchr(arg, ')'); end = strchr(arg, ')');
if (!end) if (!end) {
if (err)
memprintf(err, "missing closing ')' after arguments to ACL keyword '%s'", aclkw->kw);
goto out_free_expr; goto out_free_expr;
}
/* Parse the arguments. Note that currently we have no way to /* Parse the arguments. Note that currently we have no way to
* report parsing errors, hence the NULL in the error pointers. * report parsing errors, hence the NULL in the error pointers.
@ -1268,12 +1280,22 @@ struct acl_expr *parse_acl_expr(const char **args)
* missing. * missing.
*/ */
nbargs = make_arg_list(arg, end - arg, aclkw->arg_mask, &expr->args, nbargs = make_arg_list(arg, end - arg, aclkw->arg_mask, &expr->args,
NULL, NULL, NULL); err, NULL, NULL);
if (nbargs < 0) if (nbargs < 0) {
/* note that make_arg_list will have set <err> here */
if (err)
memprintf(err, "in argument to '%s', %s", aclkw->kw, *err);
goto out_free_expr; goto out_free_expr;
}
if (aclkw->val_args && !aclkw->val_args(expr->args, NULL)) if (aclkw->val_args && !aclkw->val_args(expr->args, err)) {
goto out_free_expr; /* invalid keyword argument */ /* invalid keyword argument, error must have been
* set by val_args().
*/
if (err)
memprintf(err, "in argument to '%s', %s", aclkw->kw, *err);
goto out_free_expr;
}
} }
else if (ARGM(aclkw->arg_mask) == 1) { else if (ARGM(aclkw->arg_mask) == 1) {
int type = (aclkw->arg_mask >> 4) & 15; int type = (aclkw->arg_mask >> 4) & 15;
@ -1282,8 +1304,11 @@ struct acl_expr *parse_acl_expr(const char **args)
* an empty one so that acl_find_targets() resolves it as * an empty one so that acl_find_targets() resolves it as
* the current one later. * the current one later.
*/ */
if (type != ARGT_FE && type != ARGT_BE && type != ARGT_TAB) if (type != ARGT_FE && type != ARGT_BE && type != ARGT_TAB) {
if (err)
memprintf(err, "ACL keyword '%s' expects %d arguments", aclkw->kw, ARGM(aclkw->arg_mask));
goto out_free_expr; goto out_free_expr;
}
/* Build an arg list containing the type as an empty string /* Build an arg list containing the type as an empty string
* and the usual STOP. * and the usual STOP.
@ -1297,12 +1322,16 @@ struct acl_expr *parse_acl_expr(const char **args)
} }
else if (ARGM(aclkw->arg_mask)) { else if (ARGM(aclkw->arg_mask)) {
/* there were some mandatory arguments */ /* there were some mandatory arguments */
if (err)
memprintf(err, "ACL keyword '%s' expects %d arguments", aclkw->kw, ARGM(aclkw->arg_mask));
goto out_free_expr; goto out_free_expr;
} }
} }
else { else {
if (arg) { if (arg) {
/* no argument expected */ /* no argument expected */
if (err)
memprintf(err, "ACL keyword '%s' takes no argument", aclkw->kw);
goto out_free_expr; goto out_free_expr;
} }
} }
@ -1319,8 +1348,11 @@ struct acl_expr *parse_acl_expr(const char **args)
if ((*args)[1] == 'i') if ((*args)[1] == 'i')
patflags |= ACL_PAT_F_IGNORE_CASE; patflags |= ACL_PAT_F_IGNORE_CASE;
else if ((*args)[1] == 'f') { else if ((*args)[1] == 'f') {
if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE)) if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE)) {
if (err)
memprintf(err, "failed to load some ACL patterns from file '%s'", args[1]);
goto out_free_expr; goto out_free_expr;
}
args++; args++;
} }
else if ((*args)[1] == '-') { else if ((*args)[1] == '-') {
@ -1337,13 +1369,19 @@ struct acl_expr *parse_acl_expr(const char **args)
while (**args) { while (**args) {
int ret; int ret;
pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern)); pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
if (!pattern) if (!pattern) {
if (err)
memprintf(err, "out of memory when parsing ACL pattern");
goto out_free_expr; goto out_free_expr;
}
pattern->flags = patflags; pattern->flags = patflags;
ret = aclkw->parse(args, pattern, &opaque); ret = aclkw->parse(args, pattern, &opaque);
if (!ret) if (!ret) {
if (err)
memprintf(err, "failed to parse some ACL patterns");
goto out_free_pattern; goto out_free_pattern;
}
LIST_ADDQ(&expr->patterns, &pattern->list); LIST_ADDQ(&expr->patterns, &pattern->list);
args += ret; args += ret;
} }
@ -1378,23 +1416,31 @@ struct acl *prune_acl(struct acl *acl) {
/* Parse an ACL with the name starting at <args>[0], and with a list of already /* Parse an ACL with the name starting at <args>[0], and with a list of already
* known ACLs in <acl>. If the ACL was not in the list, it will be added. * known ACLs in <acl>. If the ACL was not in the list, it will be added.
* A pointer to that ACL is returned. If the ACL has an empty name, then it's * A pointer to that ACL is returned. If the ACL has an empty name, then it's
* an anonymous one and it won't be merged with any other one. * an anonymous one and it won't be merged with any other one. If <err> is not
* NULL, it will be filled with an appropriate error. This pointer must be
* freeable or NULL.
* *
* args syntax: <aclname> <acl_expr> * args syntax: <aclname> <acl_expr>
*/ */
struct acl *parse_acl(const char **args, struct list *known_acl) struct acl *parse_acl(const char **args, struct list *known_acl, char **err)
{ {
__label__ out_return, out_free_acl_expr, out_free_name; __label__ out_return, out_free_acl_expr, out_free_name;
struct acl *cur_acl; struct acl *cur_acl;
struct acl_expr *acl_expr; struct acl_expr *acl_expr;
char *name; char *name;
const char *pos;
if (**args && invalid_char(*args)) if (**args && (pos = invalid_char(*args))) {
if (err)
memprintf(err, "invalid character in ACL name : '%c'", *pos);
goto out_return; goto out_return;
}
acl_expr = parse_acl_expr(args + 1); acl_expr = parse_acl_expr(args + 1, err);
if (!acl_expr) if (!acl_expr) {
/* parse_acl_expr will have filled <err> here */
goto out_return; goto out_return;
}
/* Check for args beginning with an opening parenthesis just after the /* Check for args beginning with an opening parenthesis just after the
* subject, as this is almost certainly a typo. Right now we can only * subject, as this is almost certainly a typo. Right now we can only
@ -1415,11 +1461,17 @@ struct acl *parse_acl(const char **args, struct list *known_acl)
if (!cur_acl) { if (!cur_acl) {
name = strdup(args[0]); name = strdup(args[0]);
if (!name) if (!name) {
if (err)
memprintf(err, "out of memory when parsing ACL");
goto out_free_acl_expr; goto out_free_acl_expr;
}
cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl)); cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
if (cur_acl == NULL) if (cur_acl == NULL) {
if (err)
memprintf(err, "out of memory when parsing ACL");
goto out_free_name; goto out_free_name;
}
LIST_INIT(&cur_acl->expr); LIST_INIT(&cur_acl->expr);
LIST_ADDQ(known_acl, &cur_acl->list); LIST_ADDQ(known_acl, &cur_acl->list);
@ -1470,9 +1522,11 @@ const struct {
/* Find a default ACL from the default_acl list, compile it and return it. /* Find a default ACL from the default_acl list, compile it and return it.
* If the ACL is not found, NULL is returned. In theory, it cannot fail, * If the ACL is not found, NULL is returned. In theory, it cannot fail,
* except when default ACLs are broken, in which case it will return NULL. * except when default ACLs are broken, in which case it will return NULL.
* If <known_acl> is not NULL, the ACL will be queued at its tail. * If <known_acl> is not NULL, the ACL will be queued at its tail. If <err> is
* not NULL, it will be filled with an error message if an error occurs. This
* pointer must be freeable or NULL.
*/ */
struct acl *find_acl_default(const char *acl_name, struct list *known_acl) struct acl *find_acl_default(const char *acl_name, struct list *known_acl, char **err)
{ {
__label__ out_return, out_free_acl_expr, out_free_name; __label__ out_return, out_free_acl_expr, out_free_name;
struct acl *cur_acl; struct acl *cur_acl;
@ -1485,19 +1539,31 @@ struct acl *find_acl_default(const char *acl_name, struct list *known_acl)
break; break;
} }
if (default_acl_list[index].name == NULL) if (default_acl_list[index].name == NULL) {
if (err)
memprintf(err, "no such ACL : '%s'", acl_name);
return NULL; return NULL;
}
acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr); acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr, err);
if (!acl_expr) if (!acl_expr) {
/* parse_acl_expr must have filled err here */
goto out_return; goto out_return;
}
name = strdup(acl_name); name = strdup(acl_name);
if (!name) if (!name) {
if (err)
memprintf(err, "out of memory when building default ACL '%s'", acl_name);
goto out_free_acl_expr; goto out_free_acl_expr;
}
cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl)); cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
if (cur_acl == NULL) if (cur_acl == NULL) {
if (err)
memprintf(err, "out of memory when building default ACL '%s'", acl_name);
goto out_free_name; goto out_free_name;
}
cur_acl->name = name; cur_acl->name = name;
cur_acl->requires |= acl_expr->kw->requires; cur_acl->requires |= acl_expr->kw->requires;
@ -1534,9 +1600,12 @@ struct acl_cond *prune_acl_cond(struct acl_cond *cond)
/* Parse an ACL condition starting at <args>[0], relying on a list of already /* Parse an ACL condition starting at <args>[0], relying on a list of already
* known ACLs passed in <known_acl>. The new condition is returned (or NULL in * known ACLs passed in <known_acl>. The new condition is returned (or NULL in
* case of low memory). Supports multiple conditions separated by "or". * case of low memory). Supports multiple conditions separated by "or". If
* <err> is not NULL, it will be filled with a pointer to an error message in
* case of error, that the caller is responsible for freeing. The initial
* location must either be freeable or NULL.
*/ */
struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol) struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol, char **err)
{ {
__label__ out_return, out_free_suite, out_free_term; __label__ out_return, out_free_suite, out_free_term;
int arg, neg; int arg, neg;
@ -1547,8 +1616,11 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
struct acl_cond *cond; struct acl_cond *cond;
cond = (struct acl_cond *)calloc(1, sizeof(*cond)); cond = (struct acl_cond *)calloc(1, sizeof(*cond));
if (cond == NULL) if (cond == NULL) {
if (err)
memprintf(err, "out of memory when parsing condition");
goto out_return; goto out_return;
}
LIST_INIT(&cond->list); LIST_INIT(&cond->list);
LIST_INIT(&cond->suites); LIST_INIT(&cond->suites);
@ -1588,21 +1660,29 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
while (*args[arg_end] && strcmp(args[arg_end], "}") != 0) while (*args[arg_end] && strcmp(args[arg_end], "}") != 0)
arg_end++; arg_end++;
if (!*args[arg_end]) if (!*args[arg_end]) {
if (err)
memprintf(err, "missing closing '}' in condition");
goto out_free_suite; goto out_free_suite;
}
args_new = calloc(1, (arg_end - arg + 1) * sizeof(*args_new)); args_new = calloc(1, (arg_end - arg + 1) * sizeof(*args_new));
if (!args_new) if (!args_new) {
if (err)
memprintf(err, "out of memory when parsing condition");
goto out_free_suite; goto out_free_suite;
}
args_new[0] = ""; args_new[0] = "";
memcpy(args_new + 1, args + arg + 1, (arg_end - arg) * sizeof(*args_new)); memcpy(args_new + 1, args + arg + 1, (arg_end - arg) * sizeof(*args_new));
args_new[arg_end - arg] = ""; args_new[arg_end - arg] = "";
cur_acl = parse_acl(args_new, known_acl); cur_acl = parse_acl(args_new, known_acl, err);
free(args_new); free(args_new);
if (!cur_acl) if (!cur_acl) {
/* note that parse_acl() must have filled <err> here */
goto out_free_suite; goto out_free_suite;
}
arg = arg_end; arg = arg_end;
} }
else { else {
@ -1613,15 +1693,20 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
*/ */
cur_acl = find_acl_by_name(word, known_acl); cur_acl = find_acl_by_name(word, known_acl);
if (cur_acl == NULL) { if (cur_acl == NULL) {
cur_acl = find_acl_default(word, known_acl); cur_acl = find_acl_default(word, known_acl, err);
if (cur_acl == NULL) if (cur_acl == NULL) {
/* note that find_acl_default() must have filled <err> here */
goto out_free_suite; goto out_free_suite;
}
} }
} }
cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term)); cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term));
if (cur_term == NULL) if (cur_term == NULL) {
if (err)
memprintf(err, "out of memory when parsing condition");
goto out_free_suite; goto out_free_suite;
}
cur_term->acl = cur_acl; cur_term->acl = cur_acl;
cur_term->neg = neg; cur_term->neg = neg;
@ -1629,8 +1714,11 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
if (!cur_suite) { if (!cur_suite) {
cur_suite = (struct acl_term_suite *)calloc(1, sizeof(*cur_suite)); cur_suite = (struct acl_term_suite *)calloc(1, sizeof(*cur_suite));
if (cur_term == NULL) if (cur_term == NULL) {
if (err)
memprintf(err, "out of memory when parsing condition");
goto out_free_term; goto out_free_term;
}
LIST_INIT(&cur_suite->terms); LIST_INIT(&cur_suite->terms);
LIST_ADDQ(&cond->suites, &cur_suite->list); LIST_ADDQ(&cond->suites, &cur_suite->list);
} }
@ -1653,13 +1741,19 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
* condition is returned. NULL is returned in case of error or if the first * condition is returned. NULL is returned in case of error or if the first
* word is neither "if" nor "unless". It automatically sets the file name and * word is neither "if" nor "unless". It automatically sets the file name and
* the line number in the condition for better error reporting, and adds the * the line number in the condition for better error reporting, and adds the
* ACL requirements to the proxy's acl_requires. * ACL requirements to the proxy's acl_requires. If <err> is not NULL, it will
* be filled with a pointer to an error message in case of error, that the
* caller is responsible for freeing. The initial location must either be
* freeable or NULL.
*/ */
struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args) struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args, char **err)
{ {
int pol = ACL_COND_NONE; int pol = ACL_COND_NONE;
struct acl_cond *cond = NULL; struct acl_cond *cond = NULL;
if (err)
*err = NULL;
if (!strcmp(*args, "if")) { if (!strcmp(*args, "if")) {
pol = ACL_COND_IF; pol = ACL_COND_IF;
args++; args++;
@ -1668,12 +1762,17 @@ struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, co
pol = ACL_COND_UNLESS; pol = ACL_COND_UNLESS;
args++; args++;
} }
else else {
if (err)
memprintf(err, "conditions must start with either 'if' or 'unless'");
return NULL; return NULL;
}
cond = parse_acl_cond(args, &px->acl, pol); cond = parse_acl_cond(args, &px->acl, pol, err);
if (!cond) if (!cond) {
/* note that parse_acl_cond must have filled <err> here */
return NULL; return NULL;
}
cond->file = file; cond->file = file;
cond->line = line; cond->line = line;

View File

@ -1085,6 +1085,7 @@ static int create_cond_regex_rule(const char *file, int line,
const char **cond_start) const char **cond_start)
{ {
regex_t *preg = NULL; regex_t *preg = NULL;
char *errmsg = NULL;
const char *err; const char *err;
int err_code = 0; int err_code = 0;
struct acl_cond *cond = NULL; struct acl_cond *cond = NULL;
@ -1106,9 +1107,10 @@ static int create_cond_regex_rule(const char *file, int line,
if (cond_start && if (cond_start &&
(strcmp(*cond_start, "if") == 0 || strcmp(*cond_start, "unless") == 0)) { (strcmp(*cond_start, "if") == 0 || strcmp(*cond_start, "unless") == 0)) {
if ((cond = build_acl_cond(file, line, px, cond_start)) == NULL) { if ((cond = build_acl_cond(file, line, px, cond_start, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n", Alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
file, line, cmd); file, line, cmd, errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto err; goto err;
} }
@ -2073,6 +2075,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
curproxy->bind_proc = set; curproxy->bind_proc = set;
} }
else if (!strcmp(args[0], "acl")) { /* add an ACL */ else if (!strcmp(args[0], "acl")) { /* add an ACL */
char *errmsg = NULL;
if (curproxy == &defproxy) { if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
@ -2086,9 +2090,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
} }
if (parse_acl((const char **)args + 1, &curproxy->acl) == NULL) { if (parse_acl((const char **)args + 1, &curproxy->acl, &errmsg) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing ACL '%s'.\n", Alert("parsing [%s:%d] : error detected while parsing ACL '%s' : %s.\n",
file, linenum, args[1]); file, linenum, args[1], errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -2507,6 +2512,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
curproxy->server_id_hdr_len = strlen(curproxy->server_id_hdr_name); curproxy->server_id_hdr_len = strlen(curproxy->server_id_hdr_name);
} }
else if (!strcmp(args[0], "block")) { /* early blocking based on ACLs */ else if (!strcmp(args[0], "block")) { /* early blocking based on ACLs */
char *errmsg = NULL;
if (curproxy == &defproxy) { if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
@ -2520,9 +2527,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out; goto out;
} }
if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1)) == NULL) { if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing blocking condition.\n", Alert("parsing [%s:%d] : error detected while parsing blocking condition : %s.\n",
file, linenum); file, linenum, errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -2620,10 +2628,13 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
} }
else if (strcmp(args[cur_arg], "if") == 0 || else if (strcmp(args[cur_arg], "if") == 0 ||
strcmp(args[cur_arg], "unless") == 0) { strcmp(args[cur_arg], "unless") == 0) {
cond = build_acl_cond(file, linenum, curproxy, (const char **)args + cur_arg); char *errmsg = NULL;
cond = build_acl_cond(file, linenum, curproxy, (const char **)args + cur_arg, &errmsg);
if (!cond) { if (!cond) {
Alert("parsing [%s:%d] : '%s': error detected while parsing redirect condition.\n", Alert("parsing [%s:%d] : '%s': error detected while parsing redirect condition : %s.\n",
file, linenum, args[0]); file, linenum, args[0], errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -2676,6 +2687,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
} }
else if (!strcmp(args[0], "use_backend")) { else if (!strcmp(args[0], "use_backend")) {
struct switching_rule *rule; struct switching_rule *rule;
char *errmsg = NULL;
if (curproxy == &defproxy) { if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@ -2699,9 +2711,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out; goto out;
} }
if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) { if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing switching rule.\n", Alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
file, linenum); file, linenum, errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -2716,6 +2729,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
} }
else if (strcmp(args[0], "use-server") == 0) { else if (strcmp(args[0], "use-server") == 0) {
struct server_rule *rule; struct server_rule *rule;
char *errmsg = NULL;
if (curproxy == &defproxy) { if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@ -2739,9 +2753,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out; goto out;
} }
if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) { if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing switching rule.\n", Alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
file, linenum); file, linenum, errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -2758,6 +2773,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
else if ((!strcmp(args[0], "force-persist")) || else if ((!strcmp(args[0], "force-persist")) ||
(!strcmp(args[0], "ignore-persist"))) { (!strcmp(args[0], "ignore-persist"))) {
struct persist_rule *rule; struct persist_rule *rule;
char *errmsg = NULL;
if (curproxy == &defproxy) { if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@ -2775,9 +2791,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out; goto out;
} }
if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1)) == NULL) { if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing a '%s' rule.\n", Alert("parsing [%s:%d] : error detected while parsing a '%s' rule : %s.\n",
file, linenum, args[0]); file, linenum, args[0], errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -2953,6 +2970,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
struct sticking_rule *rule; struct sticking_rule *rule;
struct pattern_expr *expr; struct pattern_expr *expr;
int myidx = 0; int myidx = 0;
char *errmsg = NULL;
const char *name = NULL; const char *name = NULL;
int flags; int flags;
@ -3028,9 +3046,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
} }
if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) { if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + myidx)) == NULL) { if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + myidx, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition.\n", Alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition : %s.\n",
file, linenum, args[0]); file, linenum, args[0], errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
free(expr); free(expr);
goto out; goto out;
@ -3070,6 +3089,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto stats_error_parsing; goto stats_error_parsing;
} else if (!strcmp(args[1], "admin")) { } else if (!strcmp(args[1], "admin")) {
struct stats_admin_rule *rule; struct stats_admin_rule *rule;
char *errmsg = NULL;
if (curproxy == &defproxy) { if (curproxy == &defproxy) {
Alert("parsing [%s:%d]: '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]); Alert("parsing [%s:%d]: '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
@ -3089,9 +3109,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) { if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule.\n", Alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule : %s.\n",
file, linenum, args[0], args[1]); file, linenum, args[0], args[1], errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -3846,6 +3867,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
err_code |= ERR_WARN; err_code |= ERR_WARN;
if (strcmp(args[1], "fail") == 0) { if (strcmp(args[1], "fail") == 0) {
char *errmsg = NULL;
/* add a condition to fail monitor requests */ /* add a condition to fail monitor requests */
if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) { if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
Alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n", Alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
@ -3854,9 +3877,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out; goto out;
} }
if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) { if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition.\n", Alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
file, linenum, args[0], args[1]); file, linenum, args[0], args[1], errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -4987,6 +5011,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
} }
else if (!strcmp(args[0], "reqadd")) { /* add request header */ else if (!strcmp(args[0], "reqadd")) { /* add request header */
struct cond_wordlist *wl; struct cond_wordlist *wl;
char *errmsg = NULL;
if (curproxy == &defproxy) { if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@ -5003,9 +5028,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
} }
if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) { if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2)) == NULL) { if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n", Alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
file, linenum, args[0]); file, linenum, args[0], errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -5082,6 +5108,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
} }
else if (!strcmp(args[0], "rspadd")) { /* add response header */ else if (!strcmp(args[0], "rspadd")) { /* add response header */
struct cond_wordlist *wl; struct cond_wordlist *wl;
char *errmsg = NULL;
if (curproxy == &defproxy) { if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@ -5098,9 +5125,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
} }
if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) { if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2)) == NULL) { if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n", Alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
file, linenum, args[0]); file, linenum, args[0], errmsg);
free(errmsg);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }

View File

@ -7506,10 +7506,12 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) { if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
struct acl_cond *cond; struct acl_cond *cond;
char *errmsg = NULL;
if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg)) == NULL) { if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg, &errmsg)) == NULL) {
Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition.\n", Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition : %s.\n",
file, linenum, args[0]); file, linenum, args[0], errmsg);
free(errmsg);
return NULL; return NULL;
} }
rule->cond = cond; rule->cond = cond;

View File

@ -962,10 +962,13 @@ static int tcp_parse_response_rule(char **args, int arg, int section_type,
} }
if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) { if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) { char *errmsg = NULL;
if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, &errmsg)) == NULL) {
snprintf(err, errlen, snprintf(err, errlen,
"error detected in %s '%s' while parsing '%s' condition", "error detected in %s '%s' while parsing '%s' condition : %s",
proxy_type_str(curpx), curpx->id, args[arg]); proxy_type_str(curpx), curpx->id, args[arg], errmsg);
free(errmsg);
return -1; return -1;
} }
} }
@ -1032,10 +1035,13 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type,
} }
if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) { if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) { char *errmsg = NULL;
if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, &errmsg)) == NULL) {
snprintf(err, errlen, snprintf(err, errlen,
"error detected in %s '%s' while parsing '%s' condition", "error detected in %s '%s' while parsing '%s' condition : %s",
proxy_type_str(curpx), curpx->id, args[arg]); proxy_type_str(curpx), curpx->id, args[arg], errmsg);
free(errmsg);
return -1; return -1;
} }
} }