]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: acl: associate "struct sample_storage" to each "struct acl_pattern"
authorThierry FOURNIER <tfournier@exceliance.fr>
Fri, 22 Nov 2013 18:14:42 +0000 (19:14 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 2 Dec 2013 22:31:33 +0000 (23:31 +0100)
This will be used later with maps. Each map will associate an entry with
a sample_storage value.

This patch changes the "parse" prototype and all the parsing methods.
The goal is to associate "struct sample_storage" to each entry of
"struct acl_pattern". Only the "parse" function can add the sample value
into the "struct acl_pattern".

include/proto/acl.h
include/types/acl.h
src/acl.c
src/proto_http.c

index 008e848f3846e4843a4d68c4bc8d39440c9f4d89..5e2e9ee28a0a7665b71fb0618d03307a4cf24ca2 100644 (file)
@@ -125,7 +125,7 @@ int acl_cond_kw_conflicts(const struct acl_cond *cond, unsigned int where, struc
  * fails, with <err> message filled. It returns -2 in "out of memory"
  * error case.
  */
-int acl_register_pattern(struct acl_expr *expr, char *text, struct acl_pattern **pattern, int patflags, char **err);
+int acl_register_pattern(struct acl_expr *expr, char *text, struct sample_storage *smp, struct acl_pattern **pattern, int patflags, char **err);
 
 /*
  * Find targets for userlist and groups in acl. Function returns the number
@@ -138,10 +138,12 @@ int acl_find_targets(struct proxy *p);
  */
 struct acl *find_acl_by_name(const char *name, struct list *head);
 
-/* This function execute the match part of the acl.
- * it return ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS
+/* This function execute the match part of the acl. It's applying
+ * acl <expr> on sample <smp>. <sample> is filled only if the pointer
+ * is not NULL. The function return ACL_PAT_FAIL, ACL_PAT_MISS or
+ * ACL_PAT_PASS
  */
-inline int acl_exec_match(struct acl_expr *expr, struct sample *smp);
+inline int acl_exec_match(struct acl_expr *expr, struct sample *smp, struct sample_storage **sample);
 
 /*
  * Registers the ACL keyword list <kwl> as a list of valid keywords for next
@@ -168,7 +170,7 @@ int init_acl();
 
 
 /* ignore the current line */
-int acl_parse_nothing(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+int acl_parse_nothing(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
 
 /* NB: For two strings to be identical, it is required that their lengths match */
 int acl_match_str(struct sample *smp, struct acl_pattern *pattern);
@@ -183,34 +185,34 @@ int acl_match_len(struct sample *smp, struct acl_pattern *pattern);
 int acl_match_int(struct sample *smp, struct acl_pattern *pattern);
 
 /* Parse an integer. It is put both in min and max. */
-int acl_parse_int(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+int acl_parse_int(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
 
 /* Parse an version. It is put both in min and max. */
-int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
 
 /* Parse a range of integers delimited by either ':' or '-'. If only one
  * integer is read, it is set as both min and max.
  */
-int acl_parse_range(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+int acl_parse_range(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
 
 /* Parse a string. It is allocated and duplicated. */
-int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+int acl_parse_str(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
 
 /* Parse a hexa binary definition. It is allocated and duplicated. */
-int acl_parse_bin(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+int acl_parse_bin(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
 
 /* Parse and concatenate strings into one. It is allocated and duplicated. */
-int acl_parse_strcat(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+int acl_parse_strcat(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
 
 /* Parse a regex. It is allocated. */
-int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+int acl_parse_reg(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
 
 /* Parse an IP address and an optional mask in the form addr[/mask].
  * The addr may either be an IPv4 address or a hostname. The mask
  * may either be a dotted mask or a number of bits. Returns 1 if OK,
  * otherwise 0.
  */
-int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+int acl_parse_ip(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
 
 /* always return false */
 int acl_match_nothing(struct sample *smp, struct acl_pattern *pattern);
index 3b3a52bd750aa779154773f5458ce92bd89438e6..322e74b97ddad961406307e7e35142717b53841b 100644 (file)
@@ -105,6 +105,14 @@ struct acl_time {
        int h2:5, m2:6;         /* 0..24:0..60. Use 24:0 for all day. */
 };
 
+/* This contain each tree indexed entry. This struct permit to associate
+ * "sample" with a tree entry. It is used with maps.
+ */
+struct acl_idx_elt {
+       struct sample_storage *smp;
+       struct ebmb_node node;
+};
+
 /* This describes one ACL pattern, which might be a single value or a tree of
  * values. All patterns for a single ACL expression are linked together. Some
  * of them might have a type (eg: IP). Right now, the types are shared with
@@ -142,6 +150,9 @@ struct acl_pattern {
        void(*freeptrbuf)(void *ptr);   /* a destructor able to free objects from the ptr */
        int len;                        /* data length when required  */
        int flags;                      /* expr or pattern flags. */
+       struct sample_storage *smp;     /* used to store a pointer to sample value associated
+                                          with the match. It is used with maps */
+
 };
 
 /* some dummy declarations to silent the compiler */
@@ -164,7 +175,7 @@ struct acl_expr;
 struct acl_keyword {
        const char *kw;
        char *fetch_kw;
-       int (*parse)(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+       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);
        /* must be after the config params */
        struct sample_fetch *smp; /* the sample fetch we depend on */
@@ -190,7 +201,7 @@ struct acl_kw_list {
  * are grouped together in order to optimize caching.
  */
 struct acl_expr {
-       int (*parse)(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+       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 list patterns;         /* list of acl_patterns */
@@ -232,7 +243,7 @@ struct acl_cond {
 };
 
 extern char *acl_match_names[ACL_MATCH_NUM];
-extern int (*acl_parse_fcts[ACL_MATCH_NUM])(const char **, struct acl_pattern *, 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 *);
 
 #endif /* _TYPES_ACL_H */
index 27c680450c9e0e42ae62c268fe1480f7e91a5c0a..ca24693df5b282d0b0e0ee2c806f7beccd2bf340 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -53,7 +53,7 @@ char *acl_match_names[ACL_MATCH_NUM] = {
        [ACL_MATCH_REG]   = "reg",
 };
 
-int (*acl_parse_fcts[ACL_MATCH_NUM])(const char **, struct acl_pattern *, int *, char **) = {
+int (*acl_parse_fcts[ACL_MATCH_NUM])(const char **, struct acl_pattern *, struct sample_storage *, int *, char **) = {
        [ACL_MATCH_FOUND] = acl_parse_nothing,
        [ACL_MATCH_BOOL]  = acl_parse_nothing,
        [ACL_MATCH_INT]   = acl_parse_int,
@@ -101,7 +101,7 @@ static int acl_find_match_name(const char *name)
  */
 
 /* ignore the current line */
-int acl_parse_nothing(const char **text, struct acl_pattern *pattern, int *opaque, char **err)
+int acl_parse_nothing(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
 {
        return 1;
 }
@@ -426,7 +426,7 @@ static void *acl_lookup_ip(struct sample *smp, struct acl_expr *expr)
 }
 
 /* Parse a string. It is allocated and duplicated. */
-int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque, char **err)
+int acl_parse_str(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
 {
        int len;
 
@@ -437,21 +437,23 @@ int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque, c
                /* we're allowed to put the data in a tree whose root is pointed
                 * to by val.tree.
                 */
-               struct ebmb_node *node;
+               struct acl_idx_elt *node;
 
                node = calloc(1, sizeof(*node) + len + 1);
                if (!node) {
                        memprintf(err, "out of memory while loading string pattern");
                        return 0;
                }
-               memcpy(node->key, *text, len + 1);
-               if (ebst_insert(pattern->val.tree, node) != node)
+               node->smp = smp;
+               memcpy(node->node.key, *text, len + 1);
+               if (ebst_insert(pattern->val.tree, &node->node) != &node->node)
                        free(node); /* was a duplicate */
                pattern->flags |= ACL_PAT_F_TREE; /* this pattern now contains a tree */
                return 1;
        }
 
        pattern->ptr.str = strdup(*text);
+       pattern->smp = smp;
        if (!pattern->ptr.str) {
                memprintf(err, "out of memory while loading string pattern");
                return 0;
@@ -461,7 +463,7 @@ int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque, c
 }
 
 /* Parse a binary written in hexa. It is allocated. */
-int acl_parse_bin(const char **text, struct acl_pattern *pattern, int *opaque, char **err)
+int acl_parse_bin(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
 {
        int len;
        const char *p = *text;
@@ -476,6 +478,7 @@ int acl_parse_bin(const char **text, struct acl_pattern *pattern, int *opaque, c
        pattern->type = SMP_T_CBIN;
        pattern->len = len >> 1;
        pattern->ptr.str = malloc(pattern->len);
+       pattern->smp = smp;
        if (!pattern->ptr.str) {
                memprintf(err, "out of memory while loading string pattern");
                return 0;
@@ -499,7 +502,7 @@ bad_input:
 
 /* Parse and concatenate all further strings into one. */
 int
-acl_parse_strcat(const char **text, struct acl_pattern *pattern, int *opaque, char **err)
+acl_parse_strcat(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
 {
 
        int len = 0, i;
@@ -510,6 +513,7 @@ acl_parse_strcat(const char **text, struct acl_pattern *pattern, int *opaque, ch
 
        pattern->type = SMP_T_CSTR;
        pattern->ptr.str = s = calloc(1, len);
+       pattern->smp = smp;
        if (!pattern->ptr.str) {
                memprintf(err, "out of memory while loading pattern");
                return 0;
@@ -530,7 +534,7 @@ static void acl_free_reg(void *ptr)
 }
 
 /* Parse a regex. It is allocated. */
-int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque, char **err)
+int acl_parse_reg(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
 {
        regex *preg;
 
@@ -548,6 +552,7 @@ int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque, c
 
        pattern->ptr.reg = preg;
        pattern->freeptrbuf = &acl_free_reg;
+       pattern->smp = smp;
        return 1;
 }
 
@@ -565,13 +570,14 @@ int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque, c
  * the caller will have to free it.
  *
  */
-int acl_parse_int(const char **text, struct acl_pattern *pattern, int *opaque, char **err)
+int acl_parse_int(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
 {
        signed long long i;
        unsigned int j, last, skip = 0;
        const char *ptr = *text;
 
        pattern->type = SMP_T_UINT;
+       pattern->smp = smp;
        while (!isdigit((unsigned char)*ptr)) {
                switch (get_std_op(ptr)) {
                case STD_OP_EQ: *opaque = 0; break;
@@ -656,7 +662,7 @@ int acl_parse_int(const char **text, struct acl_pattern *pattern, int *opaque, c
  *    acl valid_ssl       ssl_req_proto 3.0-3.1
  *
  */
-int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, int *opaque, char **err)
+int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
 {
        signed long long i;
        unsigned int j, last, skip = 0;
@@ -715,6 +721,8 @@ int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, int *op
                return 0;
        }
 
+       pattern->smp = smp;
+
        if (!last)
                pattern->val.range.min = i;
        pattern->val.range.max = i;
@@ -745,7 +753,7 @@ int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, int *op
  * may either be a dotted mask or a number of bits. Returns 1 if OK,
  * otherwise 0. NOTE: IP address patterns are typed (IPV4/IPV6).
  */
-int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque, char **err)
+int acl_parse_ip(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
 {
        struct eb_root *tree = NULL;
        if (pattern->flags & ACL_PAT_F_TREE_OK)
@@ -753,7 +761,7 @@ int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque, ch
 
        if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask)) {
                unsigned int mask = ntohl(pattern->val.ipv4.mask.s_addr);
-               struct ebmb_node *node;
+               struct acl_idx_elt *node;
                /* check if the mask is contiguous so that we can insert the
                 * network into the tree. A continuous mask has only ones on
                 * the left. This means that this mask + its lower bit added
@@ -768,9 +776,10 @@ int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque, ch
                                memprintf(err, "out of memory while loading IPv4 pattern");
                                return 0;
                        }
-                       memcpy(node->key, &pattern->val.ipv4.addr, 4); /* network byte order */
-                       node->node.pfx = mask;
-                       if (ebmb_insert_prefix(tree, node, 4) != node)
+                       node->smp = smp;
+                       memcpy(node->node.key, &pattern->val.ipv4.addr, 4); /* network byte order */
+                       node->node.node.pfx = mask;
+                       if (ebmb_insert_prefix(tree, &node->node, 4) != &node->node)
                                free(node); /* was a duplicate */
                        pattern->flags |= ACL_PAT_F_TREE;
                        return 1;
@@ -905,6 +914,7 @@ static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
  * return -2 if out of memory
  */
 int acl_register_pattern(struct acl_expr *expr, char *text,
+                         struct sample_storage *smp,
                          struct acl_pattern **pattern,
                          int patflags, char **err)
 {
@@ -933,7 +943,7 @@ int acl_register_pattern(struct acl_expr *expr, char *text,
        }
 
        (*pattern)->type = SMP_TYPES; /* unspecified type by default */
-       if (!expr->parse(args, *pattern, &opaque, err))
+       if (!expr->parse(args, *pattern, smp, &opaque, err))
                return -1;
 
        /* if the parser did not feed the tree, let's chain the pattern to the list */
@@ -993,7 +1003,7 @@ static int acl_read_patterns_from_file(struct acl_expr *expr,
                if (c == arg)
                        continue;
 
-               code = acl_register_pattern(expr, arg, &pattern, patflags, err);
+               code = acl_register_pattern(expr, arg, NULL, &pattern, patflags, err);
                if (code == -2) {
                        memprintf(err, "out of memory when loading patterns from file <%s>", filename);
                        goto out_close;
@@ -1414,7 +1424,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
                pattern->flags = patflags;
 
                pattern->type = SMP_TYPES; /* unspecified type */
-               ret = expr->parse(args, pattern, &opaque, err);
+               ret = expr->parse(args, pattern, NULL, &opaque, err);
                if (!ret)
                        goto out_free_pattern;
 
@@ -1834,13 +1844,18 @@ struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, co
        return cond;
 }
 
-/* This function execute the match part of the acl.
- * it return ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS
+/* This function execute the match part of the acl. It's applying
+ * acl <expr> on sample <smp>. <sample> is filled only if the pointer
+ * is not NULL. The function return ACL_PAT_FAIL, ACL_PAT_MISS or
+ * ACL_PAT_PASS
  */
-inline int acl_exec_match(struct acl_expr *expr, struct sample *smp)
+inline int acl_exec_match(struct acl_expr *expr, struct sample *smp,
+                          struct sample_storage **sample)
 {
        int acl_res = ACL_PAT_FAIL;
        struct acl_pattern *pattern;
+       struct ebmb_node *node = NULL;
+       struct acl_idx_elt *elt;
 
        if (expr->match == acl_match_nothing) {
                if (smp->data.uint)
@@ -1856,9 +1871,15 @@ inline int acl_exec_match(struct acl_expr *expr, struct sample *smp)
                if (!eb_is_empty(&expr->pattern_tree)) {
                        /* a tree is present, let's check what type it is */
                        if (expr->match == acl_match_str)
-                               acl_res |= acl_lookup_str(smp, expr) ? ACL_PAT_PASS : ACL_PAT_FAIL;
+                               node = acl_lookup_str(smp, expr);
                        else if (expr->match == acl_match_ip)
-                               acl_res |= acl_lookup_ip(smp, expr) ? ACL_PAT_PASS : ACL_PAT_FAIL;
+                               node = acl_lookup_ip(smp, expr);
+                       if (node) {
+                               acl_res |= ACL_PAT_PASS;
+                               elt = ebmb_entry(node, struct acl_idx_elt, node);
+                               if (sample)
+                                       *sample = elt->smp;
+                       }
                }
 
                /* call the match() function for all tests on this value */
@@ -1866,6 +1887,8 @@ inline int acl_exec_match(struct acl_expr *expr, struct sample *smp)
                        if (acl_res == ACL_PAT_PASS)
                                break;
                        acl_res |= expr->match(smp, pattern);
+                       if (sample)
+                               *sample = pattern->smp;
                }
        }
 
@@ -1937,7 +1960,7 @@ int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, v
                                        continue;
                                }
 
-                               acl_res |= acl_exec_match(expr, &smp);
+                               acl_res |= acl_exec_match(expr, &smp, NULL);
                                /*
                                 * OK now acl_res holds the result of this expression
                                 * as one of ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
index b5ad54c84877b449b0ceaabda47ed09df298e91b..e6d5fc54ba91c9b584b6758d0060b11eac916d1d 100644 (file)
@@ -8920,13 +8920,14 @@ smp_prefetch_http(struct proxy *px, struct session *s, void *l7, unsigned int op
  * We use the pre-parsed method if it is known, and store its number as an
  * integer. If it is unknown, we use the pointer and the length.
  */
-static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque, char **err)
+static int acl_parse_meth(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
 {
        int len, meth;
 
        len  = strlen(*text);
        meth = find_http_meth(*text, len);
 
+       pattern->smp = smp;
        pattern->val.i = meth;
        if (meth == HTTP_METH_OTHER) {
                pattern->ptr.str = strdup(*text);