diff --git a/include/proto/pattern.h b/include/proto/pattern.h index 0bef7e6a2..ea8cf0dfe 100644 --- a/include/proto/pattern.h +++ b/include/proto/pattern.h @@ -25,11 +25,13 @@ #include #include -struct pattern_expr *pattern_parse_expr(char **str, int *idx); +struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err_size); struct pattern *pattern_process(struct proxy *px, struct session *l4, void *l7, int dir, struct pattern_expr *expr, 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 pattern_arg **arg_p, int *arg_i); +int pattern_arg_str(const char *arg_str, struct pattern_arg **arg_p, int *arg_i); #endif diff --git a/include/proto/stick_table.h b/include/proto/stick_table.h index ce7ea1df4..4365fcdfc 100644 --- a/include/proto/stick_table.h +++ b/include/proto/stick_table.h @@ -46,9 +46,9 @@ struct stksess *stktable_touch(struct stktable *t, struct stksess *ts); struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts); struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key); struct stksess *stktable_update_key(struct stktable *table, struct stktable_key *key); -struct stktable_key *stktable_fetch_key(struct proxy *px, struct session *l4, - void *l7, int dir, struct pattern_expr *expr, - unsigned long table_type); +struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, + struct session *l4, void *l7, int dir, + struct pattern_expr *expr); int stktable_compatible_pattern(struct pattern_expr *expr, unsigned long table_type); int stktable_get_data_type(char *name); struct proxy *find_stktable(const char *name); diff --git a/include/types/pattern.h b/include/types/pattern.h index d9346d996..78614bcea 100644 --- a/include/types/pattern.h +++ b/include/types/pattern.h @@ -31,18 +31,43 @@ enum { PATTERN_TYPE_IP = 0, /* ipv4 type */ PATTERN_TYPE_INTEGER, /* unsigned 32bits integer type */ PATTERN_TYPE_STRING, /* char string type */ + PATTERN_TYPE_DATA, /* buffer type */ + PATTERN_TYPE_CONSTSTRING, /* constant char string type, data need dup before conversion */ + PATTERN_TYPE_CONSTDATA, /* constant buffer type, data need dup before conversion */ PATTERN_TYPES /* number of types, must always be last */ }; + +/* pattern arg types */ +enum { + PATTERN_ARG_TYPE_IP = 0, /* ipv4 type */ + PATTERN_ARG_TYPE_INTEGER, /* unsigned 32bits integer type */ + PATTERN_ARG_TYPE_SINTEGER, /* signed 32bits integer type */ + PATTERN_ARG_TYPE_STRING /* string type */ +}; + /* pattern fetch direction */ #define PATTERN_FETCH_REQ 1 #define PATTERN_FETCH_RTR 2 + +union pattern_arg_data { + struct in_addr ip; /* used for ipv4 type */ + uint32_t integer; /* used for unsigned 32bits integer type */ + int32_t sinteger; /* used for signed 32bits integer type */ + struct chunk str; +}; + +struct pattern_arg { + int type; /* type of arg */ + union pattern_arg_data data; /* data */ +}; + /* pattern result data */ union pattern_data { struct in_addr ip; /* used for ipv4 type */ uint32_t integer; /* used for unsigned 32bits integer type */ - struct chunk str; /* used for char string type */ + struct chunk str; /* used for char string type or buffers*/ }; /* pattern result */ @@ -54,22 +79,22 @@ struct pattern { /* pattern conversion */ struct pattern_conv { const char *kw; /* configuration keyword */ - int (*process)(const void *arg_p, + int (*process)(const struct pattern_arg *arg_p, int arg_i, union pattern_data *data); /* process function */ + int (*parse_args)(const char *arg_str, + struct pattern_arg **arg_p, + int *arg_i); /* argument parser. Can be NULL. */ unsigned int in_type; /* input needed pattern type */ unsigned int out_type; /* output pattern type */ - int (*parse_args)(const char *arg_str, - void **arg_p, - int *arg_i); /* argument parser. Can be NULL. */ }; /* pattern conversion expression */ struct pattern_conv_expr { struct list list; /* member of a pattern expression */ struct pattern_conv *conv; /* pattern conversion */ - void *arg_p; /* pointer arg, most often a string argument */ - int arg_i; /* int arg, most often the argument's length */ + struct pattern_arg *arg_p; /* pointer on args */ + int arg_i; /* number of args */ }; /* pattern fetch */ @@ -78,9 +103,12 @@ struct pattern_fetch { int (*process)(struct proxy *px, struct session *l4, void *l7, - int dir, const char *arg, - int arg_len, + int dir, const struct pattern_arg *arg_p, + int arg_i, union pattern_data *data); /* fetch processing function */ + int (*parse_args)(const char *arg_str, + struct pattern_arg **arg_p, + int *arg_i); /* argument parser. Can be NULL. */ unsigned long out_type; /* output pattern type */ int dir; /* usable directions */ }; @@ -89,8 +117,8 @@ struct pattern_fetch { struct pattern_expr { struct list list; /* member of list of pattern, currently not used */ struct pattern_fetch *fetch; /* pattern fetch */ - char *arg; /* configured keyword argument */ - int arg_len; /* configured keyword argument length */ + struct pattern_arg *arg_p; /* pointer on args */ + int arg_i; /* number of args */ struct list conv_exprs; /* list of conversion expression to apply */ }; diff --git a/include/types/stick_table.h b/include/types/stick_table.h index 4338e59cc..b83506607 100644 --- a/include/types/stick_table.h +++ b/include/types/stick_table.h @@ -37,6 +37,7 @@ enum { STKTABLE_TYPE_IP = 0, /* table key is ipv4 */ STKTABLE_TYPE_INTEGER, /* table key is unsigned 32bit integer */ STKTABLE_TYPE_STRING, /* table key is a null terminated string */ + STKTABLE_TYPE_BINARY, /* table key is a buffer of data */ STKTABLE_TYPES /* Number of types, must always be last */ }; @@ -118,6 +119,8 @@ struct stktable_type { size_t default_size; /* default key size */ }; +extern struct stktable_type stktable_types[]; + /* Sticky session. * Any additional data related to the stuck session is installed *before* * stksess (with negative offsets). This allows us to run variable-sized @@ -159,7 +162,7 @@ extern struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES]; union stktable_key_data { struct in_addr ip; /* used to store an ip key */ uint32_t integer; /* used to store an integer key */ - char buf[BUFSIZE]; /* used to store a null terminated string key */ + char buf[BUFSIZE]; /* used to store a null terminated string key or a buffer of data */ }; /* stick table key */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 1cd7d398f..3841c99f0 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2728,9 +2728,9 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) goto out; } - expr = pattern_parse_expr(args, &myidx); + expr = pattern_parse_expr(args, &myidx, trash, sizeof(trash)); if (!expr) { - Alert("parsing [%s:%d] : '%s': unknown fetch method '%s'.\n", file, linenum, args[0], args[myidx]); + Alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], trash); err_code |= ERR_ALERT | ERR_FATAL; goto out; } diff --git a/src/pattern.c b/src/pattern.c index 6a12442fc..ba8d5a01e 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -14,6 +14,7 @@ #include #include +#include #include /* static structure used on pattern_process if

is NULL*/ @@ -109,9 +110,7 @@ static struct chunk *get_trash_chunk(void) else pattern_trash_buf = pattern_trash_buf1; - trash_chunk.str = pattern_trash_buf; - trash_chunk.len = 0; - trash_chunk.size = BUFSIZE; + chunk_init(&trash_chunk, pattern_trash_buf, BUFSIZE); return &trash_chunk; } @@ -121,9 +120,7 @@ static struct chunk *get_trash_chunk(void) */ static void pattern_data_setstring(union pattern_data *data, struct chunk *c) { - data->str.str = c->str; - data->str.len = c->len; - data->str.size = c->size; + chunk_initlen(&data->str, c->str, c->size, c->len); } /******************************************************************/ @@ -172,6 +169,7 @@ static int c_int2str(union pattern_data *data) if (!pos) return 0; + trash->size = trash->size - (pos - trash->str); trash->str = pos; trash->len = strlen(pos); @@ -180,6 +178,19 @@ static int c_int2str(union pattern_data *data) return 1; } +static int c_datadup(union pattern_data *data) +{ + struct chunk *trash = get_trash_chunk(); + + trash->len = data->str.len < trash->size ? data->str.len : trash->size; + memcpy(trash->str, data->str.str, trash->len); + + pattern_data_setstring(data, trash); + + return 1; +} + + static int c_donothing(union pattern_data *data) { return 1; @@ -211,9 +222,13 @@ static int c_str2int(union pattern_data *data) typedef int (*pattern_cast_fct)(union pattern_data *data); static pattern_cast_fct pattern_casts[PATTERN_TYPES][PATTERN_TYPES] = { - { c_donothing, c_ip2int, c_ip2str }, - { c_int2ip, c_donothing, c_int2str }, - { c_str2ip, c_str2int, c_donothing }, +/* to: IP INTEGER STRING DATA CONSTSTRING CONSTDATA */ +/* from: IP */ { c_donothing, c_ip2int, c_ip2str, NULL, c_ip2str, NULL }, +/* INTEGER */ { c_int2ip, c_donothing, c_int2str, NULL, c_int2str, NULL }, +/* STRING */ { c_str2ip, c_str2int, c_donothing, c_donothing, c_donothing, c_donothing }, +/* DATA */ { NULL, NULL, NULL, c_donothing, NULL, c_donothing }, +/* CONSTSTRING */ { c_str2ip, c_str2int, c_datadup, c_datadup, c_donothing, c_donothing }, +/* CONSTDATA */ { NULL, NULL, NULL, c_datadup, NULL, NULL }, }; @@ -222,7 +237,7 @@ static pattern_cast_fct pattern_casts[PATTERN_TYPES][PATTERN_TYPES] = { * fetch keyword followed by format conversion keywords. * Returns a pointer on allocated pattern expression structure. */ -struct pattern_expr *pattern_parse_expr(char **str, int *idx) +struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err_size) { const char *endw; const char *end; @@ -230,34 +245,88 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx) struct pattern_fetch *fetch; struct pattern_conv *conv; unsigned long prev_type; + char *p; - if (!str[*idx]) + snprintf(err, err_size, "memory error."); + if (!str[*idx]) { + + snprintf(err, err_size, "missing fetch method."); goto out_error; + } end = str[*idx] + strlen(str[*idx]); endw = strchr(str[*idx], '('); if (!endw) endw = end; - else if ((end-1)[0] != ')') + else if ((end-1)[0] != ')') { + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "syntax error: missing ')' after keyword '%s'.", p); + free(p); + } goto out_error; + } fetch = find_pattern_fetch(str[*idx], endw - str[*idx]); - if (!fetch) + if (!fetch) { + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "unknown fetch method '%s'.", p); + free(p); + } goto out_error; + } + if (fetch->out_type >= PATTERN_TYPES) { - if (fetch->out_type >= PATTERN_TYPES) + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "returns type of fetch method '%s' is unknown.", p); + free(p); + } goto out_error; + } prev_type = fetch->out_type; expr = calloc(1, sizeof(struct pattern_expr)); + if (!expr) + goto out_error; LIST_INIT(&(expr->conv_exprs)); expr->fetch = fetch; if (end != endw) { - expr->arg_len = end - endw - 2; - expr->arg = my_strndup(endw + 1, expr->arg_len); + int i = end - endw - 2; + + if (!fetch->parse_args) { + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "fetch method '%s' does not support any args.", p); + free(p); + } + goto out_error; + } + p = my_strndup(endw + 1, i); + if (!p) + goto out_error; + i = fetch->parse_args(p, &expr->arg_p, &expr->arg_i); + free(p); + if (!i) { + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "invalid args in fetch method '%s'.", p); + free(p); + } + goto out_error; + } + } + else if (fetch->parse_args) { + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "missing args for fetch method '%s'.", p); + free(p); + } + goto out_error; } for (*idx += 1; *(str[*idx]); (*idx)++) { @@ -268,42 +337,85 @@ struct pattern_expr *pattern_parse_expr(char **str, int *idx) if (!endw) endw = end; - else if ((end-1)[0] != ')') + else if ((end-1)[0] != ')') { + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "syntax error, missing ')' after keyword '%s'.", p); + free(p); + } goto out_error; + } conv = find_pattern_conv(str[*idx], endw - str[*idx]); if (!conv) break; if (conv->in_type >= PATTERN_TYPES || - conv->out_type >= PATTERN_TYPES) + conv->out_type >= PATTERN_TYPES) { + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "returns type of conv method '%s' is unknown.", p); + free(p); + } goto out_error; + } /* If impossible type conversion */ - if (!pattern_casts[prev_type][conv->in_type]) + if (!pattern_casts[prev_type][conv->in_type]) { + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "conv method '%s' cannot be applied.", p); + free(p); + } goto out_error; + } prev_type = conv->out_type; conv_expr = calloc(1, sizeof(struct pattern_conv_expr)); + if (!conv_expr) + goto out_error; LIST_ADDQ(&(expr->conv_exprs), &(conv_expr->list)); conv_expr->conv = conv; if (end != endw) { int i = end - endw - 2; - char *p = my_strndup(endw + 1, i); - if (conv->parse_args) { - i = conv->parse_args(p, &conv_expr->arg_p, &conv_expr->arg_i); - free(p); - if (!i) - goto out_error; - } else { - conv_expr->arg_i = i; - conv_expr->arg_p = p; + if (!conv->parse_args) { + p = my_strndup(str[*idx], endw - str[*idx]); + + if (p) { + snprintf(err, err_size, "conv method '%s' does not support any args.", p); + free(p); + } + goto out_error; + } + + p = my_strndup(endw + 1, i); + if (!p) + goto out_error; + i = conv->parse_args(p, &conv_expr->arg_p, &conv_expr->arg_i); + free(p); + if (!i) { + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "invalid args in conv method '%s'.", p); + free(p); + } + goto out_error; } } + else if (conv->parse_args) { + p = my_strndup(str[*idx], endw - str[*idx]); + if (p) { + snprintf(err, err_size, "missing args for conv method '%s'.", p); + free(p); + } + goto out_error; + } + } + return expr; out_error: @@ -327,7 +439,7 @@ struct pattern *pattern_process(struct proxy *px, struct session *l4, void *l7, if (p == NULL) p = &spattern; - if (!expr->fetch->process(px, l4, l7, dir, expr->arg, expr->arg_len, &p->data)) + if (!expr->fetch->process(px, l4, l7, dir, expr->arg_p, expr->arg_i, &p->data)) return NULL; p->type = expr->fetch->out_type; @@ -345,28 +457,49 @@ struct pattern *pattern_process(struct proxy *px, struct session *l4, void *l7, return p; } -/* Converts an argument string to an IPv4 mask stored in network byte order in - * arg_i. Returns non-zero in case of success, 0 on error. +/* Converts an argument string mask to a pattern_arg type IP. + * Returns non-zero in case of success, 0 on error. */ -static int pattern_conv_arg_to_ipmask(const char *arg_str, void **arg_p, int *arg_i) +int pattern_arg_ipmask(const char *arg_str, struct pattern_arg **arg_p, int *arg_i) { - struct in_addr mask; + *arg_i = 1; + *arg_p = calloc(1, *arg_i*sizeof(struct pattern_arg)); + (*arg_p)->type = PATTERN_ARG_TYPE_IP; - if (!str2mask(arg_str, &mask)) + if (!str2mask(arg_str, &(*arg_p)->data.ip)) return 0; - *arg_i = mask.s_addr; return 1; } + +/* Converts an argument string to a pattern_arg type STRING. + * Returns non-zero in case of success, 0 on error. + */ +int pattern_arg_str(const char *arg_str, struct pattern_arg **arg_p, int *arg_i) +{ + *arg_i = 1; + *arg_p = calloc(1, *arg_i*sizeof(struct pattern_arg)); + (*arg_p)->type = PATTERN_ARG_TYPE_STRING; + (*arg_p)->data.str.str = strdup(arg_str); + (*arg_p)->data.str.len = strlen(arg_str); + + + return 1; +} + + /*****************************************************************/ /* Pattern format convert functions */ /*****************************************************************/ -static int pattern_conv_str2lower(const void *arg_p, int arg_i, union pattern_data *data) +static int pattern_conv_str2lower(const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) { int i; + if (!data->str.size) + return 0; + for (i = 0; i < data->str.len; i++) { if ((data->str.str[i] >= 'A') && (data->str.str[i] <= 'Z')) data->str.str[i] += 'a' - 'A'; @@ -374,10 +507,13 @@ static int pattern_conv_str2lower(const void *arg_p, int arg_i, union pattern_da return 1; } -static int pattern_conv_str2upper(const void *arg_p, int arg_i, union pattern_data *data) +static int pattern_conv_str2upper(const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) { int i; + if (!data->str.size) + return 0; + for (i = 0; i < data->str.len; i++) { if ((data->str.str[i] >= 'a') && (data->str.str[i] <= 'z')) data->str.str[i] += 'A' - 'a'; @@ -386,7 +522,7 @@ static int pattern_conv_str2upper(const void *arg_p, int arg_i, union pattern_da } /* takes the netmask in arg_i */ -static int pattern_conv_ipmask(const void *arg_p, int arg_i, union pattern_data *data) +static int pattern_conv_ipmask(const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) { data->ip.s_addr &= arg_i; return 1; @@ -394,10 +530,10 @@ static int pattern_conv_ipmask(const void *arg_p, int arg_i, union pattern_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, PATTERN_TYPE_STRING, PATTERN_TYPE_STRING }, - { "lower", pattern_conv_str2lower, PATTERN_TYPE_STRING, PATTERN_TYPE_STRING }, - { "ipmask", pattern_conv_ipmask, PATTERN_TYPE_IP, PATTERN_TYPE_IP, pattern_conv_arg_to_ipmask }, - { NULL, NULL, 0, 0 }, + { "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 }, }}; __attribute__((constructor)) diff --git a/src/proto_http.c b/src/proto_http.c index 29d8f5135..db8676932 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -8105,21 +8105,23 @@ static struct acl_kw_list acl_kws = {{ },{ */ static int pattern_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, int dir, - const char *arg, int arg_len, union pattern_data *data) + const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) { struct http_txn *txn = l7; - data->ip.s_addr = htonl(get_ip_from_hdr2(&txn->req, arg, arg_len, &txn->hdr_idx, -1)); + data->ip.s_addr = htonl(get_ip_from_hdr2(&txn->req, arg_p->data.str.str, arg_p->data.str.len, &txn->hdr_idx, -1)); return data->ip.s_addr != 0; } + + /************************************************************************/ /* All supported keywords must be declared here. */ /************************************************************************/ /* Note: must not be declared as its list will be overwritten */ static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{ - { "hdr", pattern_fetch_hdr_ip, PATTERN_TYPE_IP, PATTERN_FETCH_REQ }, - { NULL, NULL, 0, 0 }, + { "hdr", pattern_fetch_hdr_ip, pattern_arg_str, PATTERN_TYPE_IP, PATTERN_FETCH_REQ }, + { NULL, NULL, NULL, 0, 0 }, }}; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index f58d2641f..380136fc0 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -1244,7 +1244,7 @@ acl_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir, /* extract the connection's source address */ static int pattern_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir, - const char *arg, int arg_len, union pattern_data *data) + const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) { if (l4->cli_addr.ss_family != AF_INET ) return 0; @@ -1295,7 +1295,7 @@ acl_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir, /* extract the connection's destination address */ static int pattern_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir, - const char *arg, int arg_len, union pattern_data *data) + const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) { if (!(l4->flags & SN_FRT_ADDR_SET)) get_frt_addr(l4); @@ -1328,8 +1328,7 @@ acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir, static int pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir, - const char *arg, int arg_len, union pattern_data *data) - + const struct pattern_arg *arg, int i, union pattern_data *data) { if (!(l4->flags & SN_FRT_ADDR_SET)) get_frt_addr(l4); @@ -1358,10 +1357,10 @@ 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, PATTERN_TYPE_IP, PATTERN_FETCH_REQ }, - { "dst", pattern_fetch_dst, PATTERN_TYPE_IP, PATTERN_FETCH_REQ }, - { "dst_port", pattern_fetch_dport, PATTERN_TYPE_INTEGER, PATTERN_FETCH_REQ }, - { NULL, NULL, 0, 0 }, + { "src", pattern_fetch_src, NULL, PATTERN_TYPE_IP, PATTERN_FETCH_REQ }, + { "dst", pattern_fetch_dst, NULL, PATTERN_TYPE_IP, PATTERN_FETCH_REQ }, + { "dst_port", pattern_fetch_dport, NULL, PATTERN_TYPE_INTEGER, PATTERN_FETCH_REQ }, + { NULL, NULL, NULL, 0, 0 }, }}; __attribute__((constructor)) diff --git a/src/session.c b/src/session.c index 53ee39739..4d2b6054e 100644 --- a/src/session.c +++ b/src/session.c @@ -1050,7 +1050,7 @@ int process_sticking_rules(struct session *s, struct buffer *req, int an_bit) if (ret) { struct stktable_key *key; - key = stktable_fetch_key(px, s, &s->txn, PATTERN_FETCH_REQ, rule->expr, rule->table.t->type); + key = stktable_fetch_key(rule->table.t, px, s, &s->txn, PATTERN_FETCH_REQ, rule->expr); if (!key) continue; @@ -1143,7 +1143,7 @@ int process_store_rules(struct session *s, struct buffer *rep, int an_bit) if (ret) { struct stktable_key *key; - key = stktable_fetch_key(px, s, &s->txn, PATTERN_FETCH_RTR, rule->expr, rule->table.t->type); + key = stktable_fetch_key(rule->table.t, px, s, &s->txn, PATTERN_FETCH_RTR, rule->expr); if (!key) continue; diff --git a/src/stick_table.c b/src/stick_table.c index cb9b6b313..bf8df0f44 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -181,7 +181,7 @@ struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key struct ebmb_node *eb; if (t->type == STKTABLE_TYPE_STRING) - eb = ebst_lookup_len(&t->keys, key->key, key->key_len); + eb = ebst_lookup_len(&t->keys, key->key, key->key_len+1 < t->key_size ? key->key_len : t->key_size-1); else eb = ebmb_lookup(&t->keys, key->key, t->key_size); @@ -383,9 +383,10 @@ int stktable_init(struct stktable *t) /* * Configuration keywords of known table types */ -struct stktable_type stktable_types[STKTABLE_TYPES] = { { "ip", 0, 4 } , +struct stktable_type stktable_types[STKTABLE_TYPES] = {{ "ip", 0, 4 }, { "integer", 0, 4 }, - { "string", STK_F_CUSTOM_KEYSIZE, 32 } }; + { "string", STK_F_CUSTOM_KEYSIZE, 32 }, + { "binary", STK_F_CUSTOM_KEYSIZE, 32 } }; /* @@ -406,10 +407,12 @@ int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *ke if (strcmp("len", args[*myidx]) == 0) { (*myidx)++; *key_size = atol(args[*myidx]); - if ( !*key_size ) + if (!*key_size) break; - /* null terminated string needs +1 for '\0'. */ - (*key_size)++; + if (*type == STKTABLE_TYPE_STRING) { + /* null terminated string needs +1 for '\0'. */ + (*key_size)++; + } (*myidx)++; } } @@ -504,9 +507,13 @@ static void *k_str2int(union pattern_data *pdata, union stktable_key_data *kdata typedef void *(*pattern_to_key_fct)(union pattern_data *pdata, union stktable_key_data *kdata, size_t *len); static pattern_to_key_fct pattern_to_key[PATTERN_TYPES][STKTABLE_TYPES] = { - { k_ip2ip, k_ip2int, k_ip2str }, - { k_int2ip, k_int2int, k_int2str }, - { k_str2ip, k_str2int, k_str2str }, +/* table type: IP INTEGER STRING BINARY */ +/* pattern type: IP */ { k_ip2ip, k_ip2int, k_ip2str, NULL }, +/* INTEGER */ { k_int2ip, k_int2int, k_int2str, NULL }, +/* STRING */ { k_str2ip, k_str2int, k_str2str, k_str2str }, +/* DATA */ { NULL, NULL, NULL, k_str2str }, +/* CONSTSTRING */ { k_str2ip, k_str2int, k_str2str, k_str2str }, +/* CONSTDATA */ { NULL, NULL, NULL, k_str2str }, }; @@ -516,8 +523,8 @@ static pattern_to_key_fct pattern_to_key[PATTERN_TYPES][STKTABLE_TYPES] = { * no key could be extracted, or a pointer to the converted result stored in * static_table_key in format . */ -struct stktable_key *stktable_fetch_key(struct proxy *px, struct session *l4, void *l7, int dir, - struct pattern_expr *expr, unsigned long table_type) +struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *l4, void *l7, int dir, + struct pattern_expr *expr) { struct pattern *ptrn; @@ -525,12 +532,39 @@ struct stktable_key *stktable_fetch_key(struct proxy *px, struct session *l4, vo if (!ptrn) return NULL; - static_table_key.key_len = (size_t)-1; - static_table_key.key = pattern_to_key[ptrn->type][table_type](&ptrn->data, &static_table_key.data, &static_table_key.key_len); + static_table_key.key_len = t->key_size; + static_table_key.key = pattern_to_key[ptrn->type][t->type](&ptrn->data, &static_table_key.data, &static_table_key.key_len); if (!static_table_key.key) return NULL; + if ((static_table_key.key_len < t->key_size) && (t->type != STKTABLE_TYPE_STRING)) { + /* need padding with null */ + + /* assume static_table_key.key_len is less than sizeof(static_table_key.data.buf) + cause t->key_size is necessary less than sizeof(static_table_key.data) */ + + if ((char *)static_table_key.key > (char *)&static_table_key.data && + (char *)static_table_key.key < (char *)&static_table_key.data + sizeof(static_table_key.data)) { + /* key buffer is part of the static_table_key private data buffer, but is not aligned */ + + if (sizeof(static_table_key.data) - ((char *)static_table_key.key - (char *)&static_table_key.data) < t->key_size) { + /* if not remain enougth place for padding , process a realign */ + memmove(static_table_key.data.buf, static_table_key.key, static_table_key.key_len); + static_table_key.key = static_table_key.data.buf; + } + } + else if (static_table_key.key != static_table_key.data.buf) { + /* key definitly not part of the static_table_key private data buffer */ + + memcpy(static_table_key.data.buf, static_table_key.key, static_table_key.key_len); + static_table_key.key = static_table_key.data.buf; + } + + memset(static_table_key.key + static_table_key.key_len, 0, t->key_size - static_table_key.key_len); + } + + return &static_table_key; }