mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-20 21:31:28 +02:00
MINOR: acl: add acl() sample fetch
This provides a sample fetch which returns the evaluation result of the conjunction of named ACLs.
This commit is contained in:
parent
00e00fb424
commit
7fccccccea
@ -19393,6 +19393,15 @@ The sample fetch methods described in this section are usable anywhere.
|
|||||||
act_conn : integer
|
act_conn : integer
|
||||||
Returns the total number of active concurrent connections on the process.
|
Returns the total number of active concurrent connections on the process.
|
||||||
|
|
||||||
|
acl([!]<name>[,...]) : boolean
|
||||||
|
Returns true if the evaluation of all the named ACL(s) is true, otherwise
|
||||||
|
returns false. Up to 12 ACLs may be provided, each delimited by comma. Each
|
||||||
|
named ACL may be prefixed with a "!" to invert the result. If any evaluation
|
||||||
|
produces an error then the sample also returns an error.
|
||||||
|
Note that HAProxy does not perform any validation checks on the referenced
|
||||||
|
ACLs, such as whether an ACL which uses a http request sample is used in
|
||||||
|
response context. This behavior may be changed in the future.
|
||||||
|
|
||||||
always_false : boolean
|
always_false : boolean
|
||||||
Always returns the boolean "false" value. It may be used with ACLs as a
|
Always returns the boolean "false" value. It may be used with ACLs as a
|
||||||
temporary replacement for another one when adjusting configurations.
|
temporary replacement for another one when adjusting configurations.
|
||||||
|
@ -144,6 +144,12 @@ struct acl_cond {
|
|||||||
int line; /* line in the config file where the condition is declared */
|
int line; /* line in the config file where the condition is declared */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct acl_sample {
|
||||||
|
struct acl_cond cond;
|
||||||
|
struct acl_term_suite suite;
|
||||||
|
struct acl_term terms[];
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _HAPROXY_ACL_T_H */
|
#endif /* _HAPROXY_ACL_T_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -250,6 +250,12 @@
|
|||||||
#define COOKIE_DELIM_DATE '|'
|
#define COOKIE_DELIM_DATE '|'
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Max number of acl() sample fetch recursive evaluations, to avoid deep tree
|
||||||
|
// loops.
|
||||||
|
#ifndef ACL_MAX_RECURSE
|
||||||
|
#define ACL_MAX_RECURSE 1000
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CONN_RETRIES 3
|
#define CONN_RETRIES 3
|
||||||
|
|
||||||
#define CHK_CONNTIME 2000
|
#define CHK_CONNTIME 2000
|
||||||
|
103
src/acl.c
103
src/acl.c
@ -28,6 +28,7 @@
|
|||||||
#include <haproxy/sample.h>
|
#include <haproxy/sample.h>
|
||||||
#include <haproxy/stick_table.h>
|
#include <haproxy/stick_table.h>
|
||||||
#include <haproxy/tools.h>
|
#include <haproxy/tools.h>
|
||||||
|
#include <haproxy/cfgparse.h>
|
||||||
|
|
||||||
/* List head of all known ACL keywords */
|
/* List head of all known ACL keywords */
|
||||||
static struct acl_kw_list acl_keywords = {
|
static struct acl_kw_list acl_keywords = {
|
||||||
@ -576,6 +577,35 @@ struct acl *prune_acl(struct acl *acl) {
|
|||||||
return acl;
|
return acl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Walk the ACL tree, following nested acl() sample fetches, for no more than
|
||||||
|
* max_recurse evaluations. Returns -1 if a recursive loop is detected, 0 if
|
||||||
|
* the max_recurse was reached, otherwise the number of max_recurse left.
|
||||||
|
*/
|
||||||
|
static int parse_acl_recurse(struct acl *acl, struct acl_expr *expr, int max_recurse)
|
||||||
|
{
|
||||||
|
struct acl_term *term;
|
||||||
|
struct acl_sample *sample;
|
||||||
|
|
||||||
|
if (strcmp(expr->smp->fetch->kw, "acl") != 0)
|
||||||
|
return max_recurse;
|
||||||
|
|
||||||
|
if (--max_recurse <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sample = (struct acl_sample *)expr->smp->arg_p->data.ptr;
|
||||||
|
list_for_each_entry(term, &sample->suite.terms, list) {
|
||||||
|
if (term->acl == acl)
|
||||||
|
return -1;
|
||||||
|
list_for_each_entry(expr, &term->acl->expr, list) {
|
||||||
|
max_recurse = parse_acl_recurse(acl, expr, max_recurse);
|
||||||
|
if (max_recurse <= 0)
|
||||||
|
return max_recurse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_recurse;
|
||||||
|
}
|
||||||
|
|
||||||
/* 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
|
||||||
@ -623,7 +653,16 @@ struct acl *parse_acl(const char **args, struct list *known_acl, char **err, str
|
|||||||
else
|
else
|
||||||
cur_acl = NULL;
|
cur_acl = NULL;
|
||||||
|
|
||||||
if (!cur_acl) {
|
if (cur_acl) {
|
||||||
|
int ret = parse_acl_recurse(cur_acl, acl_expr, ACL_MAX_RECURSE);
|
||||||
|
if (ret <= 0) {
|
||||||
|
if (ret < 0)
|
||||||
|
memprintf(err, "have a recursive loop");
|
||||||
|
else
|
||||||
|
memprintf(err, "too deep acl() tree");
|
||||||
|
goto out_free_acl_expr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
name = strdup(args[0]);
|
name = strdup(args[0]);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
memprintf(err, "out of memory when parsing ACL");
|
memprintf(err, "out of memory when parsing ACL");
|
||||||
@ -1254,6 +1293,61 @@ void free_acl_cond(struct acl_cond *cond)
|
|||||||
free(cond);
|
free(cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int smp_fetch_acl(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
||||||
|
{
|
||||||
|
struct acl_sample *acl_sample = (struct acl_sample *)args->data.ptr;
|
||||||
|
enum acl_test_res ret;
|
||||||
|
|
||||||
|
ret = acl_exec_cond(&acl_sample->cond, smp->px, smp->sess, smp->strm, smp->opt);
|
||||||
|
if (ret == ACL_TEST_MISS)
|
||||||
|
return 0;
|
||||||
|
smp->data.u.sint = ret == ACL_TEST_PASS;
|
||||||
|
smp->data.type = SMP_T_BOOL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int smp_fetch_acl_parse(struct arg *args, char **err_msg)
|
||||||
|
{
|
||||||
|
struct acl_sample *acl_sample;
|
||||||
|
char *name;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; args[i].type != ARGT_STOP; i++)
|
||||||
|
;
|
||||||
|
acl_sample = calloc(1, sizeof(struct acl_sample) + sizeof(struct acl_term) * i);
|
||||||
|
LIST_INIT(&acl_sample->suite.terms);
|
||||||
|
LIST_INIT(&acl_sample->cond.suites);
|
||||||
|
LIST_APPEND(&acl_sample->cond.suites, &acl_sample->suite.list);
|
||||||
|
acl_sample->cond.val = ~0U; // the keyword is valid everywhere for now.
|
||||||
|
|
||||||
|
args->data.ptr = acl_sample;
|
||||||
|
|
||||||
|
for (i = 0; args[i].type != ARGT_STOP; i++) {
|
||||||
|
name = args[i].data.str.area;
|
||||||
|
if (name[0] == '!') {
|
||||||
|
acl_sample->terms[i].neg = 1;
|
||||||
|
name++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(acl_sample->terms[i].acl = find_acl_by_name(name, &curproxy->acl))) {
|
||||||
|
memprintf(err_msg, "ACL '%s' not found", name);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
acl_sample->cond.use |= acl_sample->terms[i].acl->use;
|
||||||
|
acl_sample->cond.val &= acl_sample->terms[i].acl->val;
|
||||||
|
|
||||||
|
LIST_APPEND(&acl_sample->suite.terms, &acl_sample->terms[i].list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(acl_sample);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* All supported sample and ACL keywords must be declared here. */
|
/* All supported sample and ACL keywords must be declared here. */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
@ -1267,6 +1361,13 @@ static struct acl_kw_list acl_kws = {ILH, {
|
|||||||
|
|
||||||
INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
|
INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
|
||||||
|
|
||||||
|
static struct sample_fetch_kw_list smp_kws = {ILH, {
|
||||||
|
{ "acl", smp_fetch_acl, ARG12(1,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR), smp_fetch_acl_parse, SMP_T_BOOL, SMP_USE_CONST },
|
||||||
|
{ /* END */ },
|
||||||
|
}};
|
||||||
|
|
||||||
|
INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* c-indent-level: 8
|
* c-indent-level: 8
|
||||||
|
Loading…
x
Reference in New Issue
Block a user