]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: pattern: add an argument validation callback to pattern descriptors
authorWilly Tarreau <w@1wt.eu>
Fri, 20 Apr 2012 13:52:36 +0000 (15:52 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 8 May 2012 18:57:13 +0000 (20:57 +0200)
This is used to validate that arguments are coherent. For instance,
payload_lv expects that the last arg (if any) is not more negative
than the sum of the first two. The error is reported if any.

include/types/pattern.h
src/pattern.c
src/proto_http.c
src/proto_tcp.c

index c3718862d7567a749c30f01681b8125a333c4133..42dac41ac0c73b7c78588f63cde5c92aca19fb84 100644 (file)
@@ -65,6 +65,8 @@ struct pattern_conv {
        int (*process)(const struct arg *arg_p,
                       union pattern_data *data); /* process function */
        unsigned int arg_mask;                    /* arguments (ARG*()) */
+       int (*val_args)(struct arg *arg_p,
+                       char **err_msg);          /* argument validation function */
        unsigned int in_type;                     /* input needed pattern type */
        unsigned int out_type;                    /* output pattern type */
 };
@@ -85,6 +87,8 @@ struct pattern_fetch {
                       int dir, const struct arg *arg_p,
                       union pattern_data *data); /* fetch processing function */
        unsigned int arg_mask;                    /* arguments (ARG*()) */
+       int (*val_args)(struct arg *arg_p,
+                       char **err_msg);          /* argument validation function */
        unsigned long out_type;                   /* output pattern type */
        int dir;                                  /* usable directions */
 };
index 670eff7d52a2b1e307a592b9a5c79444a477173a..c2de92d4d229e227c91a10f709dc95f08898d686 100644 (file)
@@ -316,6 +316,8 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err
        expr->fetch = fetch;
 
        if (end != endw) {
+               char *err_msg;
+
                if (!fetch->arg_mask) {
                        p = my_strndup(str[*idx], endw - str[*idx]);
                        if (p) {
@@ -333,6 +335,16 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err
                        }
                        goto out_error;
                }
+
+               if (fetch->val_args && !fetch->val_args(expr->arg_p, &err_msg)) {
+                       p = my_strndup(str[*idx], endw - str[*idx]);
+                       if (p) {
+                               snprintf(err, err_size, "invalid args in fetch method '%s' : %s.", p, err_msg);
+                               free(p);
+                       }
+                       free(err_msg);
+                       goto out_error;
+               }
        }
        else if (fetch->arg_mask) {
                p = my_strndup(str[*idx], endw - str[*idx]);
@@ -393,6 +405,8 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err
                conv_expr->conv = conv;
 
                if (end != endw) {
+                       char *err_msg;
+
                        if (!conv->arg_mask) {
                                p = my_strndup(str[*idx], endw - str[*idx]);
 
@@ -411,6 +425,16 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err
                                }
                                goto out_error;
                        }
+
+                       if (conv->val_args && !conv->val_args(conv_expr->arg_p, &err_msg)) {
+                               p = my_strndup(str[*idx], endw - str[*idx]);
+                               if (p) {
+                                       snprintf(err, err_size, "invalid args in conv method '%s' : %s.", p, err_msg);
+                                       free(p);
+                               }
+                               free(err_msg);
+                               goto out_error;
+                       }
                }
                else if (conv->arg_mask) {
                        p = my_strndup(str[*idx], endw - str[*idx]);
@@ -505,9 +529,9 @@ static int pattern_conv_ipmask(const struct arg *arg_p, union pattern_data *data
 
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct pattern_conv_kw_list pattern_conv_kws = {{ },{
-       { "upper",  pattern_conv_str2upper, 0,            PATTERN_TYPE_STRING, PATTERN_TYPE_STRING },
-       { "lower",  pattern_conv_str2lower, 0,            PATTERN_TYPE_STRING, PATTERN_TYPE_STRING },
-       { "ipmask", pattern_conv_ipmask,    ARG1(1,MSK4), PATTERN_TYPE_IP,     PATTERN_TYPE_IP },
+       { "upper",  pattern_conv_str2upper, 0,            NULL, PATTERN_TYPE_STRING, PATTERN_TYPE_STRING },
+       { "lower",  pattern_conv_str2lower, 0,            NULL, PATTERN_TYPE_STRING, PATTERN_TYPE_STRING },
+       { "ipmask", pattern_conv_ipmask,    ARG1(1,MSK4), NULL, PATTERN_TYPE_IP,     PATTERN_TYPE_IP },
        { NULL, NULL, 0, 0, 0 },
 }};
 
index 7809b7adabe7e0037f4a233c45b9aed1498c2a53..f099913ad92af4ab61d8a9b9b75877e2582c2517 100644 (file)
@@ -8533,16 +8533,15 @@ pattern_fetch_set_cookie(struct proxy *px, struct session *l4, void *l7, int dir
        return found;
 }
 
-
 /************************************************************************/
 /*             All supported keywords must be declared here.            */
 /************************************************************************/
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{
-       { "hdr",        pattern_fetch_hdr,        ARG1(1,STR), PATTERN_TYPE_STRING, PATTERN_FETCH_REQ },
-       { "url_param",  pattern_fetch_url_param,  ARG1(1,STR), PATTERN_TYPE_STRING, PATTERN_FETCH_REQ },
-       { "cookie",     pattern_fetch_cookie,     ARG1(1,STR), PATTERN_TYPE_STRING, PATTERN_FETCH_REQ },
-       { "set-cookie", pattern_fetch_set_cookie, ARG1(1,STR), PATTERN_TYPE_STRING, PATTERN_FETCH_RTR },
+       { "hdr",        pattern_fetch_hdr,        ARG1(1,STR), NULL, PATTERN_TYPE_STRING, PATTERN_FETCH_REQ },
+       { "url_param",  pattern_fetch_url_param,  ARG1(1,STR), NULL, PATTERN_TYPE_STRING, PATTERN_FETCH_REQ },
+       { "cookie",     pattern_fetch_cookie,     ARG1(1,STR), NULL, PATTERN_TYPE_STRING, PATTERN_FETCH_REQ },
+       { "set-cookie", pattern_fetch_set_cookie, ARG1(1,STR), NULL, PATTERN_TYPE_STRING, PATTERN_FETCH_RTR },
        { NULL, NULL, 0, 0, 0 },
 }};
 
index 52d5cafa4c9fd7659339b7aee528d0154503e076..715f1e90682bbb818b7b5e4d3cdcffc596a8bce8 100644 (file)
@@ -1493,6 +1493,50 @@ pattern_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir
        return 1;
 }
 
+/* This function is used to validate the arguments passed to a "payload" fetch
+ * keyword. This keyword expects two positive integers, with the second one
+ * being strictly positive. It is assumed that the types are already the correct
+ * ones. Returns 0 on error, non-zero if OK. If <err_msg> 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.
+ */
+static int val_payload(struct arg *arg, char **err_msg)
+{
+       if (!arg[1].data.uint) {
+               if (err_msg)
+                       memprintf(err_msg, "payload length must be > 0");
+               return 0;
+       }
+       return 1;
+}
+
+/* This function is used to validate the arguments passed to a "payload_lv" fetch
+ * keyword. This keyword allows two positive integers and an optional signed one,
+ * with the second one being strictly positive and the third one being greater than
+ * the opposite of the two others if negative. It is assumed that the types are
+ * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> 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.
+ */
+static int val_payload_lv(struct arg *arg, char **err_msg)
+{
+       if (!arg[1].data.uint) {
+               if (err_msg)
+                       memprintf(err_msg, "payload length must be > 0");
+               return 0;
+       }
+
+       if (arg[2].type == ARGT_SINT &&
+           (int)(arg[0].data.uint + arg[1].data.uint + arg[2].data.sint) < 0) {
+               if (err_msg)
+                       memprintf(err_msg, "payload offset too negative");
+               return 0;
+       }
+       return 1;
+}
+
 static struct cfg_kw_list cfg_kws = {{ },{
        { CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
        { CFG_LISTEN, "tcp-response", tcp_parse_tcp_rep },
@@ -1512,14 +1556,14 @@ static struct acl_kw_list acl_kws = {{ },{
 
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{
-       { "src",         pattern_fetch_src,       0,                      PATTERN_TYPE_IP,        PATTERN_FETCH_REQ },
-       { "src6",        pattern_fetch_src6,      0,                      PATTERN_TYPE_IPV6,      PATTERN_FETCH_REQ },
-       { "dst",         pattern_fetch_dst,       0,                      PATTERN_TYPE_IP,        PATTERN_FETCH_REQ },
-       { "dst6",        pattern_fetch_dst6,      0,                      PATTERN_TYPE_IPV6,      PATTERN_FETCH_REQ },
-       { "dst_port",    pattern_fetch_dport,     0,                      PATTERN_TYPE_INTEGER,   PATTERN_FETCH_REQ },
-       { "payload",     pattern_fetch_payload,   ARG2(2,UINT,UINT),      PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR },
-       { "payload_lv",  pattern_fetch_payloadlv, ARG3(2,UINT,UINT,SINT), PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR },
-       { "rdp_cookie",  pattern_fetch_rdp_cookie, ARG1(1,STR),           PATTERN_TYPE_CONSTSTRING, PATTERN_FETCH_REQ },
+       { "src",         pattern_fetch_src,       0,                      NULL,           PATTERN_TYPE_IP,        PATTERN_FETCH_REQ },
+       { "src6",        pattern_fetch_src6,      0,                      NULL,           PATTERN_TYPE_IPV6,      PATTERN_FETCH_REQ },
+       { "dst",         pattern_fetch_dst,       0,                      NULL,           PATTERN_TYPE_IP,        PATTERN_FETCH_REQ },
+       { "dst6",        pattern_fetch_dst6,      0,                      NULL,           PATTERN_TYPE_IPV6,      PATTERN_FETCH_REQ },
+       { "dst_port",    pattern_fetch_dport,     0,                      NULL,           PATTERN_TYPE_INTEGER,   PATTERN_FETCH_REQ },
+       { "payload",     pattern_fetch_payload,   ARG2(2,UINT,UINT),      val_payload,    PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR },
+       { "payload_lv",  pattern_fetch_payloadlv, ARG3(2,UINT,UINT,SINT), val_payload_lv, PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR },
+       { "rdp_cookie",  pattern_fetch_rdp_cookie, ARG1(1,STR),           NULL,           PATTERN_TYPE_CONSTSTRING, PATTERN_FETCH_REQ },
        { NULL, NULL, 0, 0, 0 },
 }};