From 9fcb984b174671d6913b3c4698847a3d33b063d2 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 20 Apr 2012 14:45:49 +0200 Subject: [PATCH] MEDIUM: pattern: use the standard arg parser We don't need the pattern-specific args parsers anymore, make use of the common parser instead. We still need to improve this by adding a validation function to report abnormal argument values or combinations. We don't report precise parsing errors yet but this was not previously done either. --- include/proto/pattern.h | 3 - include/types/pattern.h | 6 +- src/pattern.c | 67 ++++---------------- src/proto_http.c | 10 +-- src/proto_tcp.c | 133 +++++----------------------------------- 5 files changed, 36 insertions(+), 183 deletions(-) diff --git a/include/proto/pattern.h b/include/proto/pattern.h index ef2c5480ce..e0fb3eb6eb 100644 --- a/include/proto/pattern.h +++ b/include/proto/pattern.h @@ -33,7 +33,4 @@ struct pattern *pattern_process(struct proxy *px, struct session *l4, struct pattern *p); void pattern_register_fetches(struct pattern_fetch_kw_list *psl); void pattern_register_convs(struct pattern_conv_kw_list *psl); - -int pattern_arg_ipmask(const char *arg_str, struct arg **arg_p); -int pattern_arg_str(const char *arg_str, struct arg **arg_p); #endif diff --git a/include/types/pattern.h b/include/types/pattern.h index 1014856609..c3718862d7 100644 --- a/include/types/pattern.h +++ b/include/types/pattern.h @@ -64,8 +64,7 @@ struct pattern_conv { const char *kw; /* configuration keyword */ int (*process)(const struct arg *arg_p, union pattern_data *data); /* process function */ - int (*parse_args)(const char *arg_str, - struct arg **arg_p); /* argument parser. May be NULL. */ + unsigned int arg_mask; /* arguments (ARG*()) */ unsigned int in_type; /* input needed pattern type */ unsigned int out_type; /* output pattern type */ }; @@ -85,8 +84,7 @@ struct pattern_fetch { void *l7, int dir, const struct arg *arg_p, union pattern_data *data); /* fetch processing function */ - int (*parse_args)(const char *arg_str, - struct arg **arg_p); /* argument parser. Can be NULL. */ + unsigned int arg_mask; /* arguments (ARG*()) */ unsigned long out_type; /* output pattern type */ int dir; /* usable directions */ }; diff --git a/src/pattern.c b/src/pattern.c index 72c0b34594..670eff7d52 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -315,9 +316,7 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err expr->fetch = fetch; if (end != endw) { - int i = end - endw - 2; - - if (!fetch->parse_args) { + if (!fetch->arg_mask) { p = my_strndup(str[*idx], endw - str[*idx]); if (p) { snprintf(err, err_size, "fetch method '%s' does not support any args.", p); @@ -325,12 +324,8 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err } goto out_error; } - p = my_strndup(endw + 1, i); - if (!p) - goto out_error; - i = fetch->parse_args(p, &expr->arg_p); - free(p); - if (!i) { + + if (make_arg_list(endw + 1, end - endw - 2, fetch->arg_mask, &expr->arg_p, NULL, NULL, NULL) < 0) { p = my_strndup(str[*idx], endw - str[*idx]); if (p) { snprintf(err, err_size, "invalid args in fetch method '%s'.", p); @@ -339,7 +334,7 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err goto out_error; } } - else if (fetch->parse_args) { + else if (fetch->arg_mask) { p = my_strndup(str[*idx], endw - str[*idx]); if (p) { snprintf(err, err_size, "missing args for fetch method '%s'.", p); @@ -398,9 +393,7 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err conv_expr->conv = conv; if (end != endw) { - int i = end - endw - 2; - - if (!conv->parse_args) { + if (!conv->arg_mask) { p = my_strndup(str[*idx], endw - str[*idx]); if (p) { @@ -410,12 +403,7 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err goto out_error; } - p = my_strndup(endw + 1, i); - if (!p) - goto out_error; - i = conv->parse_args(p, &conv_expr->arg_p); - free(p); - if (!i) { + if (make_arg_list(endw + 1, end - endw - 2, conv->arg_mask, &conv_expr->arg_p, NULL, NULL, NULL) < 0) { p = my_strndup(str[*idx], endw - str[*idx]); if (p) { snprintf(err, err_size, "invalid args in conv method '%s'.", p); @@ -424,7 +412,7 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err goto out_error; } } - else if (conv->parse_args) { + else if (conv->arg_mask) { p = my_strndup(str[*idx], endw - str[*idx]); if (p) { snprintf(err, err_size, "missing args for conv method '%s'.", p); @@ -476,37 +464,6 @@ struct pattern *pattern_process(struct proxy *px, struct session *l4, void *l7, return p; } -/* Converts an argument string mask to a arg type IP. - * Returns non-zero in case of success, 0 on error. - */ -int pattern_arg_ipmask(const char *arg_str, struct arg **arg_p) -{ - *arg_p = calloc(2, sizeof(struct arg)); - (*arg_p)->type = ARGT_IPV4; - arg_p[1]->type = ARGT_STOP; - - if (!str2mask(arg_str, &(*arg_p)->data.ipv4)) - return 0; - - return 1; -} - - -/* Converts an argument string to a arg type STRING. - * Returns non-zero in case of success, 0 on error. - */ -int pattern_arg_str(const char *arg_str, struct arg **arg_p) -{ - *arg_p = calloc(2, sizeof(struct arg)); - (*arg_p)->type = ARGT_STR; - (*arg_p)->data.str.str = strdup(arg_str); - (*arg_p)->data.str.len = strlen(arg_str); - arg_p[1]->type = ARGT_STOP; - - return 1; -} - - /*****************************************************************/ /* Pattern format convert functions */ /*****************************************************************/ @@ -548,10 +505,10 @@ static int pattern_conv_ipmask(const struct arg *arg_p, union pattern_data *data /* Note: must not be declared as its list will be overwritten */ static struct pattern_conv_kw_list pattern_conv_kws = {{ },{ - { "upper", pattern_conv_str2upper, NULL, PATTERN_TYPE_STRING, PATTERN_TYPE_STRING }, - { "lower", pattern_conv_str2lower, NULL, PATTERN_TYPE_STRING, PATTERN_TYPE_STRING }, - { "ipmask", pattern_conv_ipmask, pattern_arg_ipmask, PATTERN_TYPE_IP, PATTERN_TYPE_IP }, - { NULL, NULL, NULL, 0, 0 }, + { "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 }, + { NULL, NULL, 0, 0, 0 }, }}; __attribute__((constructor)) diff --git a/src/proto_http.c b/src/proto_http.c index da7fa339ba..7809b7adab 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -8539,11 +8539,11 @@ pattern_fetch_set_cookie(struct proxy *px, struct session *l4, void *l7, int dir /************************************************************************/ /* Note: must not be declared as its list will be overwritten */ static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{ - { "hdr", pattern_fetch_hdr, pattern_arg_str, PATTERN_TYPE_STRING, PATTERN_FETCH_REQ }, - { "url_param", pattern_fetch_url_param, pattern_arg_str, PATTERN_TYPE_STRING, PATTERN_FETCH_REQ }, - { "cookie", pattern_fetch_cookie, pattern_arg_str, PATTERN_TYPE_STRING, PATTERN_FETCH_REQ }, - { "set-cookie", pattern_fetch_set_cookie, pattern_arg_str, PATTERN_TYPE_STRING, PATTERN_FETCH_RTR }, - { NULL, NULL, NULL, 0, 0 }, + { "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 }, + { NULL, NULL, 0, 0, 0 }, }}; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index a0e315ddc5..52d5cafa4c 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -1388,75 +1389,6 @@ pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir, return 1; } -static int -pattern_arg_fetch_payloadlv(const char *arg, struct arg **arg_p) -{ - int member = 0; - int len_offset = 0; - int len_size = 0; - int buf_offset = 0; - int relative = 0; - int arg_len = strlen(arg); - int i; - - for (i = 0; i < arg_len; i++) { - if (arg[i] == ',') { - member++; - } else if (member == 0) { - if (arg[i] < '0' || arg[i] > '9') - return 0; - - len_offset = 10 * len_offset + arg[i] - '0'; - } else if (member == 1) { - if (arg[i] < '0' || arg[i] > '9') - return 0; - - len_size = 10 * len_size + arg[i] - '0'; - } else if (member == 2) { - if (!relative && !buf_offset && arg[i] == '+') { - relative = 1; - continue; - } else if (!relative && !buf_offset && arg[i] == '-') { - relative = 2; - continue; - } else if (arg[i] < '0' || arg[i] > '9') - return 0; - - buf_offset = 10 * buf_offset + arg[i] - '0'; - } - } - - if (member < 1) - return 0; - - if (!len_size) - return 0; - - if (member == 1) { - buf_offset = len_offset + len_size; - } - else if (relative == 1) { - buf_offset = len_offset + len_size + buf_offset; - } - else if (relative == 2) { - if (len_offset + len_size < buf_offset) - return 0; - - buf_offset = len_offset + len_size - buf_offset; - } - - *arg_p = calloc(4, sizeof(struct arg)); - (*arg_p)[0].type = ARGT_UINT; - (*arg_p)[0].data.uint = len_offset; - (*arg_p)[1].type = ARGT_UINT; - (*arg_p)[1].data.uint = len_size; - (*arg_p)[2].type = ARGT_UINT; - (*arg_p)[2].data.uint = buf_offset; - (*arg_p)[3].type = ARGT_STOP; - - return 1; -} - static int pattern_fetch_payloadlv(struct proxy *px, struct session *l4, void *l7, int dir, const struct arg *arg_p, union pattern_data *data) @@ -1490,6 +1422,13 @@ pattern_fetch_payloadlv(struct proxy *px, struct session *l4, void *l7, int dir, if (!buf_size) return 0; + /* buf offset may be implicit, absolute or relative */ + buf_offset = len_offset + len_size; + if (arg_p[2].type == ARGT_UINT) + buf_offset = arg_p[2].data.uint; + else if (arg_p[2].type == ARGT_SINT) + buf_offset += arg_p[2].data.sint; + if (buf_offset + buf_size > b->i) return 0; @@ -1499,44 +1438,6 @@ pattern_fetch_payloadlv(struct proxy *px, struct session *l4, void *l7, int dir, return 1; } -static int -pattern_arg_fetch_payload (const char *arg, struct arg **arg_p) -{ - int member = 0; - int buf_offset = 0; - int buf_size = 0; - int arg_len = strlen(arg); - int i; - - for (i = 0 ; i < arg_len ; i++) { - if (arg[i] == ',') { - member++; - } else if (member == 0) { - if (arg[i] < '0' || arg[i] > '9') - return 0; - - buf_offset = 10 * buf_offset + arg[i] - '0'; - } else if (member == 1) { - if (arg[i] < '0' || arg[i] > '9') - return 0; - - buf_size = 10 * buf_size + arg[i] - '0'; - } - } - - if (!buf_size) - return 0; - - *arg_p = calloc(3, sizeof(struct arg)); - (*arg_p)[0].type = ARGT_UINT; - (*arg_p)[0].data.uint = buf_offset; - (*arg_p)[1].type = ARGT_UINT; - (*arg_p)[1].data.uint = buf_size; - (*arg_p)[2].type = ARGT_STOP; - - return 1; -} - static int pattern_fetch_payload(struct proxy *px, struct session *l4, void *l7, int dir, const struct arg *arg_p, union pattern_data *data) @@ -1611,15 +1512,15 @@ static struct acl_kw_list acl_kws = {{ },{ /* Note: must not be declared as its list will be overwritten */ static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{ - { "src", pattern_fetch_src, NULL, PATTERN_TYPE_IP, PATTERN_FETCH_REQ }, - { "src6", pattern_fetch_src6, NULL, PATTERN_TYPE_IPV6, PATTERN_FETCH_REQ }, - { "dst", pattern_fetch_dst, NULL, PATTERN_TYPE_IP, PATTERN_FETCH_REQ }, - { "dst6", pattern_fetch_dst6, NULL, PATTERN_TYPE_IPV6, PATTERN_FETCH_REQ }, - { "dst_port", pattern_fetch_dport, NULL, PATTERN_TYPE_INTEGER, PATTERN_FETCH_REQ }, - { "payload", pattern_fetch_payload, pattern_arg_fetch_payload, PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR }, - { "payload_lv", pattern_fetch_payloadlv, pattern_arg_fetch_payloadlv, PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR }, - { "rdp_cookie", pattern_fetch_rdp_cookie, pattern_arg_str, PATTERN_TYPE_CONSTSTRING, PATTERN_FETCH_REQ }, - { NULL, NULL, NULL, 0, 0 }, + { "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 }, + { NULL, NULL, 0, 0, 0 }, }}; __attribute__((constructor))