diff --git a/include/proto/pattern.h b/include/proto/pattern.h index c49f53d58..1daf3bbb4 100644 --- a/include/proto/pattern.h +++ b/include/proto/pattern.h @@ -54,11 +54,12 @@ static inline int pat_find_match_name(const char *name) } /* This function executes a pattern match on a sample. It applies pattern - * to sample . If is not NULL, a pointer to an optional sample - * associated to the matching patterned will be put there. The function returns - * PAT_MATCH or PAT_NOMATCH. + * to sample . The function returns NULL if the sample dont match. It returns + * non-null if the sample match. If is true and the sample match, the + * function returns the matched pattern. In many cases, this pattern can be a + * static buffer. */ -enum pat_match_res pattern_exec_match(struct pattern_expr *expr, struct sample *smp, struct sample_storage **sample, struct pattern **pat, struct pattern_tree **elt); +struct pattern *pattern_exec_match(struct pattern_expr *expr, struct sample *smp, int fill); /* * diff --git a/src/acl.c b/src/acl.c index 78c3f307d..37fd8f4b6 100644 --- a/src/acl.c +++ b/src/acl.c @@ -39,9 +39,12 @@ static struct acl_kw_list acl_keywords = { }; /* input values are 0 or 3, output is the same */ -static inline enum acl_test_res pat2acl(enum pat_match_res res) +static inline enum acl_test_res pat2acl(struct pattern *pat) { - return (enum acl_test_res)res; + if (pat) + return ACL_TEST_PASS; + else + return ACL_TEST_FAIL; } /* @@ -1053,7 +1056,7 @@ enum acl_test_res acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct continue; } - acl_res |= pat2acl(pattern_exec_match(&expr->pat, &smp, NULL, NULL, NULL)); + acl_res |= pat2acl(pattern_exec_match(&expr->pat, &smp, 0)); /* * OK now acl_res holds the result of this expression * as one of ACL_TEST_FAIL, ACL_TEST_MISS or ACL_TEST_PASS. diff --git a/src/dumpstats.c b/src/dumpstats.c index afd333cf8..01f5d37e2 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -4827,10 +4827,10 @@ static int stats_map_lookup(struct stream_interface *si) struct sample_storage *smp; struct sample sample; struct pattern *pat; - struct pattern_tree *elt; - enum pat_match_res res; - struct sockaddr_in addr; - char addr_str[INET_ADDRSTRLEN]; + struct sockaddr_storage addr; + char s_addr[INET_ADDRSTRLEN]; + char s_mask[INET_ADDRSTRLEN]; + char s_addr6[INET6_ADDRSTRLEN]; switch (appctx->st2) { case STAT_ST_INIT: @@ -4850,9 +4850,7 @@ static int stats_map_lookup(struct stream_interface *si) sample.flags |= SMP_F_CONST; sample.data.str.len = appctx->ctx.map.chunk.len; sample.data.str.str = appctx->ctx.map.chunk.str; - pat = NULL; - elt = NULL; - res = pattern_exec_match(appctx->ctx.map.desc->pat, &sample, &smp, &pat, &elt); + pat = pattern_exec_match(appctx->ctx.map.desc->pat, &sample, 1); /* build return message: set type of match */ /**/ if (appctx->ctx.map.desc->pat->match == NULL) @@ -4885,9 +4883,8 @@ static int stats_map_lookup(struct stream_interface *si) chunk_appendf(&trash, "unknown(%p), ", appctx->ctx.map.desc->pat->match); /* Display no match, and set default value */ - if (res == PAT_NOMATCH) { + if (!pat) { chunk_appendf(&trash, "no-match, "); - smp = appctx->ctx.map.desc->def; } /* Display match and match info */ @@ -4895,46 +4892,61 @@ static int stats_map_lookup(struct stream_interface *si) /* display match */ chunk_appendf(&trash, "match, "); - /* display search mode */ - if (elt) + /* display index mode */ + if (pat->flags & PAT_F_TREE) chunk_appendf(&trash, "tree, "); else chunk_appendf(&trash, "list, "); - /* display search options */ - if (pat) { - /* case sensitive */ - if (pat->flags & PAT_F_IGNORE_CASE) - chunk_appendf(&trash, "case-insensitive, "); - else - chunk_appendf(&trash, "case-sensitive, "); + /* case sensitive */ + if (pat->flags & PAT_F_IGNORE_CASE) + chunk_appendf(&trash, "case-insensitive, "); + else + chunk_appendf(&trash, "case-sensitive, "); - /* display source */ - if (pat->flags & PAT_F_FROM_FILE) - chunk_appendf(&trash, "from-file, "); + /* display source */ + if (pat->flags & PAT_F_FROM_FILE) + chunk_appendf(&trash, "from-file, "); + + /* display string */ + if (appctx->ctx.map.desc->pat->match == pat_match_str || + appctx->ctx.map.desc->pat->match == pat_match_str || + appctx->ctx.map.desc->pat->match == pat_match_beg || + appctx->ctx.map.desc->pat->match == pat_match_sub || + appctx->ctx.map.desc->pat->match == pat_match_dir || + appctx->ctx.map.desc->pat->match == pat_match_dom || + appctx->ctx.map.desc->pat->match == pat_match_end) { + chunk_appendf(&trash, "match=\"%s\", ", pat->ptr.str); } - - /* display match expresion */ - if (elt) { - if (appctx->ctx.map.desc->pat->match == pat_match_str) { - chunk_appendf(&trash, "match=\"%s\", ", elt->node.key); + else if (appctx->ctx.map.desc->pat->match == pat_match_ip) { + /* display IPv4/v6 */ + if (pat->type == SMP_T_IPV4) { + ((struct sockaddr_in *)&addr)->sin_family = AF_INET; + memcpy(&((struct sockaddr_in *)&addr)->sin_addr, &pat->val.ipv4.addr, + sizeof(pat->val.ipv4.addr)); + if (addr_to_str(&addr, s_addr, INET_ADDRSTRLEN)) { + memcpy(&((struct sockaddr_in *)&addr)->sin_addr, &pat->val.ipv4.mask, + sizeof(pat->val.ipv4.mask)); + if (addr_to_str(&addr, s_mask, INET_ADDRSTRLEN)) + chunk_appendf(&trash, "match=\"%s/%s\", ", s_addr, s_mask); + } } - /* only IPv4 */ - else if (appctx->ctx.map.desc->pat->match == pat_match_ip) { - /* convert ip */ - memcpy(&addr.sin_addr, elt->node.key, 4); - addr.sin_family = AF_INET; - if (addr_to_str((struct sockaddr_storage *)&addr, addr_str, INET_ADDRSTRLEN)) - chunk_appendf(&trash, "match=\"%s/%d\", ", addr_str, elt->node.node.pfx); + else if (pat->type == SMP_T_IPV6) { + ((struct sockaddr_in6 *)&addr)->sin6_family = AF_INET6; + memcpy(&((struct sockaddr_in6 *)&addr)->sin6_addr, &pat->val.ipv6.addr, + sizeof(pat->val.ipv6.addr)); + if (addr_to_str(&addr, s_addr6, INET6_ADDRSTRLEN)) + chunk_appendf(&trash, "match=\"%s/%d\", ", s_addr6, pat->val.ipv6.mask); } } } /* display return value */ - if (!smp) { + if (!pat || !pat->smp) { chunk_appendf(&trash, "return=nothing\n"); } else { + smp = pat->smp; memcpy(&sample.data, &smp->data, sizeof(sample.data)); sample.type = smp->type; if (sample_casts[sample.type][SMP_T_STR] && diff --git a/src/map.c b/src/map.c index e48408aa3..c244bb7d3 100644 --- a/src/map.c +++ b/src/map.c @@ -457,24 +457,38 @@ static int sample_load_map(struct arg *arg, struct sample_conv *conv, char **err static int sample_conv_map(const struct arg *arg_p, struct sample *smp) { struct map_descriptor *desc; - struct sample_storage *sample; - enum pat_match_res ret; + struct pattern *pat; /* get config */ desc = arg_p[0].data.map; /* Execute the match function. */ - ret = pattern_exec_match(desc->pat, smp, &sample, NULL, NULL); - if (ret != PAT_MATCH) { - if (!desc->def) - return 0; - sample = desc->def; + pat = pattern_exec_match(desc->pat, smp, 1); + + /* Match case. */ + if (pat) { + /* Copy sample. */ + if (pat->smp) { + smp->type = pat->smp->type; + smp->flags |= SMP_F_CONST; + memcpy(&smp->data, &pat->smp->data, sizeof(smp->data)); + return 1; + } + + /* Return just int sample containing 1. */ + smp->type = SMP_T_UINT; + smp->data.uint= 1; + return 1; } - /* copy new data */ - smp->type = sample->type; + /* If no default value avalaible, the converter fails. */ + if (!desc->def) + return 0; + + /* Return the default value. */ + smp->type = desc->def->type; smp->flags |= SMP_F_CONST; - memcpy(&smp->data, &sample->data, sizeof(smp->data)); + memcpy(&smp->data, &desc->def->data, sizeof(smp->data)); return 1; } diff --git a/src/pattern.c b/src/pattern.c index d41e08633..aa6a3d43b 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -105,6 +105,9 @@ int pat_match_types[PAT_MATCH_NUM] = { [PAT_MATCH_REG] = SMP_T_STR, }; +/* this struct is used to return information */ +static struct pattern static_pattern; + /* * * The following functions are not exported and are used by internals process @@ -1059,19 +1062,18 @@ int pattern_read_from_file(struct pattern_expr *expr, return ret; } -/* This function matches a sample against a set of patterns presented in - * pattern expression . Upon success, if is not NULL, it is fed - * with the pointer associated with the matching pattern. This function returns - * PAT_NOMATCH or PAT_MATCH. +/* This function executes a pattern match on a sample. It applies pattern + * to sample . The function returns NULL if the sample dont match. It returns + * non-null if the sample match. If is true and the sample match, the + * function returns the matched pattern. In many cases, this pattern can be a + * static buffer. */ -enum pat_match_res pattern_exec_match(struct pattern_expr *expr, struct sample *smp, - struct sample_storage **sample, - struct pattern **pat, struct pattern_tree **idx_elt) +struct pattern *pattern_exec_match(struct pattern_expr *expr, struct sample *smp, int fill) { enum pat_match_res pat_res = PAT_NOMATCH; - struct pattern_list *pattern; + struct pattern_list *pattern = NULL; struct ebmb_node *node = NULL; - struct pattern_tree *elt; + struct pattern_tree *elt = NULL; if (expr->match == pat_match_nothing) { if (smp->data.uint) @@ -1097,27 +1099,62 @@ enum pat_match_res pattern_exec_match(struct pattern_expr *expr, struct sample * if (node) { pat_res |= PAT_MATCH; elt = ebmb_entry(node, struct pattern_tree, node); - if (sample) - *sample = elt->smp; - if (idx_elt) - *idx_elt = elt; } } /* call the match() function for all tests on this value */ - list_for_each_entry(pattern, &expr->patterns, list) { - if (pat_res == PAT_MATCH) - break; - if (sample_convert(smp, pattern->pat.expect_type)) - pat_res |= expr->match(smp, &pattern->pat); - if (sample) - *sample = pattern->pat.smp; - if (pat) - *pat = &pattern->pat; + if (pat_res != PAT_MATCH) { + list_for_each_entry(pattern, &expr->patterns, list) { + if (sample_convert(smp, pattern->pat.expect_type)) + pat_res |= expr->match(smp, &pattern->pat); + if (pat_res == PAT_MATCH) + break; + } } } - return pat_res; + if (pat_res == PAT_MATCH) { + static_pattern.flags = 0; + if (fill) { + /* fill with boolean */ + if (expr->match == NULL || + expr->match == pat_match_nothing) { + static_pattern.smp = NULL; + static_pattern.type = SMP_T_BOOL; + static_pattern.val.i = 1; + return &static_pattern; + } + + /* fill with ipv4 */ + if (expr->match == pat_match_ip && elt) { + static_pattern.smp = elt->smp;; + static_pattern.flags |= PAT_F_TREE; + static_pattern.type = SMP_T_IPV4; + memcpy(&static_pattern.val.ipv4.addr, &elt->node.key, 4); + if (!cidr2dotted(elt->node.node.pfx, &static_pattern.val.ipv4.mask)) + return NULL; + return &static_pattern; + } + + /* fill with string */ + if (expr->match == pat_match_str && elt) { + static_pattern.smp = elt->smp;; + static_pattern.flags |= PAT_F_TREE; + static_pattern.type = SMP_T_STR; + static_pattern.ptr.str = (char *)elt->node.key; + return &static_pattern; + } + + /* return the pattern */ + return &pattern->pat; + } + + /* Return uninitialized pattern. The content must not be used by the caller */ + return &static_pattern; + } + + /* No match */ + return NULL; } /* This function browse the pattern expr to lookup the key . On