mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-21 22:01:31 +02:00
MEDIUM: pattern: create pattern expression
This new structure contains the data needed for pattern matching. It's the first step to the complete independance of the pattern matching.
This commit is contained in:
parent
ed66c297c2
commit
d163e1ce30
@ -35,14 +35,14 @@
|
|||||||
* fails, with <err> message filled. It returns -2 in "out of memory"
|
* fails, with <err> message filled. It returns -2 in "out of memory"
|
||||||
* error case.
|
* error case.
|
||||||
*/
|
*/
|
||||||
int acl_register_pattern(struct acl_expr *expr, char *text, struct sample_storage *smp, struct acl_pattern **pattern, int patflags, char **err);
|
int acl_register_pattern(struct pattern_expr *expr, char *text, struct sample_storage *smp, struct acl_pattern **pattern, int patflags, char **err);
|
||||||
|
|
||||||
/* This function executes a pattern match on a sample. It applies pattern <expr>
|
/* This function executes a pattern match on a sample. It applies pattern <expr>
|
||||||
* to sample <smp>. If <sample> is not NULL, a pointer to an optional sample
|
* to sample <smp>. If <sample> is not NULL, a pointer to an optional sample
|
||||||
* associated to the matching patterned will be put there. The function returns
|
* associated to the matching patterned will be put there. The function returns
|
||||||
* ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
|
* ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
|
||||||
*/
|
*/
|
||||||
inline int acl_exec_match(struct acl_expr *expr, struct sample *smp, struct sample_storage **sample);
|
inline int acl_exec_match(struct pattern_expr *expr, struct sample *smp, struct sample_storage **sample);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
@ -128,9 +128,9 @@ int acl_match_ip(struct sample *smp, struct acl_pattern *pattern);
|
|||||||
*/
|
*/
|
||||||
int acl_match_reg(struct sample *smp, struct acl_pattern *pattern);
|
int acl_match_reg(struct sample *smp, struct acl_pattern *pattern);
|
||||||
|
|
||||||
int acl_read_patterns_from_file(struct acl_expr *expr, const char *filename, int patflags, char **err);
|
int acl_read_patterns_from_file(struct pattern_expr *expr, const char *filename, int patflags, char **err);
|
||||||
void free_pattern(struct acl_pattern *pat);
|
void free_pattern(struct acl_pattern *pat);
|
||||||
void free_pattern_list(struct list *head);
|
void prune_pattern_expr(struct pattern_expr *expr);
|
||||||
void free_pattern_tree(struct eb_root *root);
|
void init_pattern_expr(struct pattern_expr *expr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -105,17 +105,13 @@ struct acl_kw_list {
|
|||||||
/*
|
/*
|
||||||
* Description of an ACL expression.
|
* Description of an ACL expression.
|
||||||
* The expression is part of a list. It contains pointers to the keyword, the
|
* The expression is part of a list. It contains pointers to the keyword, the
|
||||||
* parse and match functions which default to the keyword's, the sample fetch
|
* sample fetch descriptor which defaults to the keyword's, and the associated
|
||||||
* descriptor which also defaults to the keyword's, and a list or tree of
|
* pattern matching. The structure is organized so that the hot parts are
|
||||||
* patterns to test against. The structure is organized so that the hot parts
|
* grouped together in order to optimize caching.
|
||||||
* are grouped together in order to optimize caching.
|
|
||||||
*/
|
*/
|
||||||
struct acl_expr {
|
struct acl_expr {
|
||||||
int (*parse)(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
|
|
||||||
int (*match)(struct sample *smp, struct acl_pattern *pattern);
|
|
||||||
struct sample_expr *smp; /* the sample expression we depend on */
|
struct sample_expr *smp; /* the sample expression we depend on */
|
||||||
struct list patterns; /* list of acl_patterns */
|
struct pattern_expr pat; /* the pattern matching expression */
|
||||||
struct eb_root pattern_tree; /* may be used for lookup in large datasets */
|
|
||||||
struct list list; /* chaining */
|
struct list list; /* chaining */
|
||||||
const char *kw; /* points to the ACL kw's name or fetch's name (must not free) */
|
const char *kw; /* points to the ACL kw's name or fetch's name (must not free) */
|
||||||
};
|
};
|
||||||
|
@ -121,6 +121,18 @@ struct acl_pattern {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Description of a pattern expression.
|
||||||
|
* It contains pointers to the parse and match functions, and a list or tree of
|
||||||
|
* patterns to test against. The structure is organized so that the hot parts
|
||||||
|
* are grouped together in order to optimize caching.
|
||||||
|
*/
|
||||||
|
struct pattern_expr {
|
||||||
|
int (*parse)(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
|
||||||
|
int (*match)(struct sample *smp, struct acl_pattern *pattern);
|
||||||
|
struct list patterns; /* list of acl_patterns */
|
||||||
|
struct eb_root pattern_tree; /* may be used for lookup in large datasets */
|
||||||
|
};
|
||||||
|
|
||||||
extern char *acl_match_names[ACL_MATCH_NUM];
|
extern char *acl_match_names[ACL_MATCH_NUM];
|
||||||
extern int (*acl_parse_fcts[ACL_MATCH_NUM])(const char **, struct acl_pattern *, struct sample_storage *, int *, char **);
|
extern int (*acl_parse_fcts[ACL_MATCH_NUM])(const char **, struct acl_pattern *, struct sample_storage *, int *, char **);
|
||||||
extern int (*acl_match_fcts[ACL_MATCH_NUM])(struct sample *, struct acl_pattern *);
|
extern int (*acl_match_fcts[ACL_MATCH_NUM])(struct sample *, struct acl_pattern *);
|
||||||
|
50
src/acl.c
50
src/acl.c
@ -107,9 +107,7 @@ static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
|
|||||||
{
|
{
|
||||||
struct arg *arg;
|
struct arg *arg;
|
||||||
|
|
||||||
free_pattern_list(&expr->patterns);
|
prune_pattern_expr(&expr->pat);
|
||||||
free_pattern_tree(&expr->pattern_tree);
|
|
||||||
LIST_INIT(&expr->patterns);
|
|
||||||
|
|
||||||
for (arg = expr->smp->arg_p; arg; arg++) {
|
for (arg = expr->smp->arg_p; arg; arg++) {
|
||||||
if (arg->type == ARGT_STOP)
|
if (arg->type == ARGT_STOP)
|
||||||
@ -171,30 +169,30 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
|
|||||||
goto out_return;
|
goto out_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init_pattern_expr(&expr->pat);
|
||||||
|
|
||||||
expr->kw = aclkw ? aclkw->kw : smp->fetch->kw;
|
expr->kw = aclkw ? aclkw->kw : smp->fetch->kw;
|
||||||
LIST_INIT(&expr->patterns);
|
expr->pat.parse = aclkw ? aclkw->parse : NULL;
|
||||||
expr->pattern_tree = EB_ROOT_UNIQUE;
|
expr->pat.match = aclkw ? aclkw->match : NULL;
|
||||||
expr->parse = aclkw ? aclkw->parse : NULL;
|
|
||||||
expr->match = aclkw ? aclkw->match : NULL;
|
|
||||||
expr->smp = aclkw ? NULL : smp;
|
expr->smp = aclkw ? NULL : smp;
|
||||||
|
|
||||||
if (!expr->parse) {
|
if (!expr->pat.parse) {
|
||||||
/* some types can be automatically converted */
|
/* some types can be automatically converted */
|
||||||
|
|
||||||
switch (expr->smp ? expr->smp->fetch->out_type : aclkw->smp->out_type) {
|
switch (expr->smp ? expr->smp->fetch->out_type : aclkw->smp->out_type) {
|
||||||
case SMP_T_BOOL:
|
case SMP_T_BOOL:
|
||||||
expr->parse = acl_parse_fcts[ACL_MATCH_BOOL];
|
expr->pat.parse = acl_parse_fcts[ACL_MATCH_BOOL];
|
||||||
expr->match = acl_match_fcts[ACL_MATCH_BOOL];
|
expr->pat.match = acl_match_fcts[ACL_MATCH_BOOL];
|
||||||
break;
|
break;
|
||||||
case SMP_T_SINT:
|
case SMP_T_SINT:
|
||||||
case SMP_T_UINT:
|
case SMP_T_UINT:
|
||||||
expr->parse = acl_parse_fcts[ACL_MATCH_INT];
|
expr->pat.parse = acl_parse_fcts[ACL_MATCH_INT];
|
||||||
expr->match = acl_match_fcts[ACL_MATCH_INT];
|
expr->pat.match = acl_match_fcts[ACL_MATCH_INT];
|
||||||
break;
|
break;
|
||||||
case SMP_T_IPV4:
|
case SMP_T_IPV4:
|
||||||
case SMP_T_IPV6:
|
case SMP_T_IPV6:
|
||||||
expr->parse = acl_parse_fcts[ACL_MATCH_IP];
|
expr->pat.parse = acl_parse_fcts[ACL_MATCH_IP];
|
||||||
expr->match = acl_match_fcts[ACL_MATCH_IP];
|
expr->pat.match = acl_match_fcts[ACL_MATCH_IP];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -430,7 +428,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
|
|||||||
|
|
||||||
/* Additional check to protect against common mistakes */
|
/* Additional check to protect against common mistakes */
|
||||||
cur_type = smp_expr_output_type(expr->smp);
|
cur_type = smp_expr_output_type(expr->smp);
|
||||||
if (expr->parse && cur_type != SMP_T_BOOL && !*args[1]) {
|
if (expr->pat.parse && cur_type != SMP_T_BOOL && !*args[1]) {
|
||||||
Warning("parsing acl keyword '%s' :\n"
|
Warning("parsing acl keyword '%s' :\n"
|
||||||
" no pattern to match against were provided, so this ACL will never match.\n"
|
" no pattern to match against were provided, so this ACL will never match.\n"
|
||||||
" If this is what you intended, please add '--' to get rid of this warning.\n"
|
" If this is what you intended, please add '--' to get rid of this warning.\n"
|
||||||
@ -453,19 +451,19 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
|
|||||||
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 (!expr->parse) {
|
if (!expr->pat.parse) {
|
||||||
memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
|
memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
|
||||||
goto out_free_expr;
|
goto out_free_expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!acl_read_patterns_from_file(expr, args[1], patflags | ACL_PAT_F_FROM_FILE, err))
|
if (!acl_read_patterns_from_file(&expr->pat, args[1], patflags | ACL_PAT_F_FROM_FILE, err))
|
||||||
goto out_free_expr;
|
goto out_free_expr;
|
||||||
args++;
|
args++;
|
||||||
}
|
}
|
||||||
else if ((*args)[1] == 'm') {
|
else if ((*args)[1] == 'm') {
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
if (!LIST_ISEMPTY(&expr->patterns) || !eb_is_empty(&expr->pattern_tree)) {
|
if (!LIST_ISEMPTY(&expr->pat.patterns) || !eb_is_empty(&expr->pat.pattern_tree)) {
|
||||||
memprintf(err, "'-m' must only be specified before patterns and files in parsing ACL expression");
|
memprintf(err, "'-m' must only be specified before patterns and files in parsing ACL expression");
|
||||||
goto out_free_expr;
|
goto out_free_expr;
|
||||||
}
|
}
|
||||||
@ -492,8 +490,8 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
|
|||||||
cur_type == SMP_T_BIN ||
|
cur_type == SMP_T_BIN ||
|
||||||
cur_type == SMP_T_CSTR ||
|
cur_type == SMP_T_CSTR ||
|
||||||
cur_type == SMP_T_CBIN))) {
|
cur_type == SMP_T_CBIN))) {
|
||||||
expr->parse = acl_parse_fcts[idx];
|
expr->pat.parse = acl_parse_fcts[idx];
|
||||||
expr->match = acl_match_fcts[idx];
|
expr->pat.match = acl_match_fcts[idx];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memprintf(err, "matching method '%s' cannot be used with fetch keyword '%s'", args[1], expr->kw);
|
memprintf(err, "matching method '%s' cannot be used with fetch keyword '%s'", args[1], expr->kw);
|
||||||
@ -510,7 +508,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
|
|||||||
args++;
|
args++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!expr->parse) {
|
if (!expr->pat.parse) {
|
||||||
memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
|
memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
|
||||||
goto out_free_expr;
|
goto out_free_expr;
|
||||||
}
|
}
|
||||||
@ -527,11 +525,11 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
|
|||||||
pattern->flags = patflags;
|
pattern->flags = patflags;
|
||||||
|
|
||||||
pattern->type = SMP_TYPES; /* unspecified type */
|
pattern->type = SMP_TYPES; /* unspecified type */
|
||||||
ret = expr->parse(args, pattern, NULL, &opaque, err);
|
ret = expr->pat.parse(args, pattern, NULL, &opaque, err);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
goto out_free_pattern;
|
goto out_free_pattern;
|
||||||
|
|
||||||
LIST_ADDQ(&expr->patterns, &pattern->list);
|
LIST_ADDQ(&expr->pat.patterns, &pattern->list);
|
||||||
args += ret;
|
args += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1012,7 +1010,7 @@ int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, v
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
acl_res |= acl_exec_match(expr, &smp, NULL);
|
acl_res |= acl_exec_match(&expr->pat, &smp, NULL);
|
||||||
/*
|
/*
|
||||||
* OK now acl_res holds the result of this expression
|
* OK now acl_res holds the result of this expression
|
||||||
* as one of ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
|
* as one of ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
|
||||||
@ -1136,14 +1134,14 @@ int acl_find_targets(struct proxy *p)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LIST_ISEMPTY(&expr->patterns)) {
|
if (LIST_ISEMPTY(&expr->pat.patterns)) {
|
||||||
Alert("proxy %s: acl %s %s(): no groups specified.\n",
|
Alert("proxy %s: acl %s %s(): no groups specified.\n",
|
||||||
p->id, acl->name, expr->kw);
|
p->id, acl->name, expr->kw);
|
||||||
cfgerr++;
|
cfgerr++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(pattern, &expr->patterns, list) {
|
list_for_each_entry(pattern, &expr->pat.patterns, list) {
|
||||||
/* this keyword only has one argument */
|
/* this keyword only has one argument */
|
||||||
pattern->val.group_mask = auth_resolve_groups(expr->smp->arg_p->data.usr, pattern->ptr.str);
|
pattern->val.group_mask = auth_resolve_groups(expr->smp->arg_p->data.usr, pattern->ptr.str);
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ int acl_match_bin(struct sample *smp, struct acl_pattern *pattern)
|
|||||||
/* Lookup a string in the expression's pattern tree. The node is returned if it
|
/* Lookup a string in the expression's pattern tree. The node is returned if it
|
||||||
* exists, otherwise NULL.
|
* exists, otherwise NULL.
|
||||||
*/
|
*/
|
||||||
static void *acl_lookup_str(struct sample *smp, struct acl_expr *expr)
|
static void *acl_lookup_str(struct sample *smp, struct pattern_expr *expr)
|
||||||
{
|
{
|
||||||
/* data are stored in a tree */
|
/* data are stored in a tree */
|
||||||
struct ebmb_node *node;
|
struct ebmb_node *node;
|
||||||
@ -389,7 +389,7 @@ int acl_match_ip(struct sample *smp, struct acl_pattern *pattern)
|
|||||||
/* Lookup an IPv4 address in the expression's pattern tree using the longest
|
/* Lookup an IPv4 address in the expression's pattern tree using the longest
|
||||||
* match method. The node is returned if it exists, otherwise NULL.
|
* match method. The node is returned if it exists, otherwise NULL.
|
||||||
*/
|
*/
|
||||||
static void *acl_lookup_ip(struct sample *smp, struct acl_expr *expr)
|
static void *acl_lookup_ip(struct sample *smp, struct pattern_expr *expr)
|
||||||
{
|
{
|
||||||
struct in_addr *s;
|
struct in_addr *s;
|
||||||
|
|
||||||
@ -807,11 +807,24 @@ void free_pattern_tree(struct eb_root *root)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void prune_pattern_expr(struct pattern_expr *expr)
|
||||||
|
{
|
||||||
|
free_pattern_list(&expr->patterns);
|
||||||
|
free_pattern_tree(&expr->pattern_tree);
|
||||||
|
LIST_INIT(&expr->patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_pattern_expr(struct pattern_expr *expr)
|
||||||
|
{
|
||||||
|
LIST_INIT(&expr->patterns);
|
||||||
|
expr->pattern_tree = EB_ROOT_UNIQUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* return 1 if the process is ok
|
/* return 1 if the process is ok
|
||||||
* return -1 if the parser fail. The err message is filled.
|
* return -1 if the parser fail. The err message is filled.
|
||||||
* return -2 if out of memory
|
* return -2 if out of memory
|
||||||
*/
|
*/
|
||||||
int acl_register_pattern(struct acl_expr *expr, char *text,
|
int acl_register_pattern(struct pattern_expr *expr, char *text,
|
||||||
struct sample_storage *smp,
|
struct sample_storage *smp,
|
||||||
struct acl_pattern **pattern,
|
struct acl_pattern **pattern,
|
||||||
int patflags, char **err)
|
int patflags, char **err)
|
||||||
@ -856,7 +869,7 @@ int acl_register_pattern(struct acl_expr *expr, char *text,
|
|||||||
/* Reads patterns from a file. If <err_msg> is non-NULL, an error message will
|
/* Reads patterns from a file. If <err_msg> is non-NULL, an error message will
|
||||||
* be returned there on errors and the caller will have to free it.
|
* be returned there on errors and the caller will have to free it.
|
||||||
*/
|
*/
|
||||||
int acl_read_patterns_from_file(struct acl_expr *expr,
|
int acl_read_patterns_from_file(struct pattern_expr *expr,
|
||||||
const char *filename, int patflags,
|
const char *filename, int patflags,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
@ -926,7 +939,7 @@ int acl_read_patterns_from_file(struct acl_expr *expr,
|
|||||||
* is not NULL. The function return ACL_PAT_FAIL, ACL_PAT_MISS or
|
* is not NULL. The function return ACL_PAT_FAIL, ACL_PAT_MISS or
|
||||||
* ACL_PAT_PASS
|
* ACL_PAT_PASS
|
||||||
*/
|
*/
|
||||||
inline int acl_exec_match(struct acl_expr *expr, struct sample *smp,
|
inline int acl_exec_match(struct pattern_expr *expr, struct sample *smp,
|
||||||
struct sample_storage **sample)
|
struct sample_storage **sample)
|
||||||
{
|
{
|
||||||
int acl_res = ACL_PAT_FAIL;
|
int acl_res = ACL_PAT_FAIL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user