MEDIUM: samples: move payload-based fetches and ACLs to their own file
The file acl.c is a real mess, it both contains functions to parse and
process ACLs, and some sample extraction functions which act on buffers.
Some other payload analysers were arbitrarily dispatched to proto_tcp.c.
So now we're moving all payload-based fetches and ACLs to payload.c
which is capable of extracting data from buffers and rely on everything
that is protocol-independant. That way we can safely inflate this file
and only use the other ones when some fetches are really specific (eg:
HTTP, SSL, ...).
As a result of this cleanup, the following new sample fetches became
available even if they're not really useful :
always_false, always_true, rep_ssl_hello_type, rdp_cookie_cnt,
req_len, req_ssl_hello_type, req_ssl_sni, req_ssl_ver, wait_end
The function 'acl_fetch_nothing' was wrong and never used anywhere so it
was removed.
The "rdp_cookie" sample fetch used to have a mandatory argument while it
was optional in ACLs, which are supposed to iterate over RDP cookies. So
we're making it optional as a fetch too, and it will return the first one.
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 7ad825e..3d2efcd 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1,7 +1,7 @@
/*
* AF_INET/AF_INET6 SOCK_STREAM protocol layer (tcp)
*
- * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2013 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -1403,125 +1403,9 @@
/************************************************************************/
-/* All supported sample fetch functios must be declared here */
+/* All supported sample fetch functions must be declared here */
/************************************************************************/
-/* Fetch the request RDP cookie identified in the args, or any cookie if no arg
- * is passed. It is usable both for ACL and for samples. Note: this decoder
- * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument
- * is a string (cookie name), other types will lead to undefined behaviour.
- */
-int
-smp_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
- const struct arg *args, struct sample *smp)
-{
- int bleft;
- const unsigned char *data;
-
- if (!l4 || !l4->req)
- return 0;
-
- smp->flags = 0;
- smp->type = SMP_T_CSTR;
-
- bleft = l4->req->buf->i;
- if (bleft <= 11)
- goto too_short;
-
- data = (const unsigned char *)l4->req->buf->p + 11;
- bleft -= 11;
-
- if (bleft <= 7)
- goto too_short;
-
- if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
- goto not_cookie;
-
- data += 7;
- bleft -= 7;
-
- while (bleft > 0 && *data == ' ') {
- data++;
- bleft--;
- }
-
- if (args) {
-
- if (bleft <= args->data.str.len)
- goto too_short;
-
- if ((data[args->data.str.len] != '=') ||
- strncasecmp(args->data.str.str, (const char *)data, args->data.str.len) != 0)
- goto not_cookie;
-
- data += args->data.str.len + 1;
- bleft -= args->data.str.len + 1;
- } else {
- while (bleft > 0 && *data != '=') {
- if (*data == '\r' || *data == '\n')
- goto not_cookie;
- data++;
- bleft--;
- }
-
- if (bleft < 1)
- goto too_short;
-
- if (*data != '=')
- goto not_cookie;
-
- data++;
- bleft--;
- }
-
- /* data points to cookie value */
- smp->data.str.str = (char *)data;
- smp->data.str.len = 0;
-
- while (bleft > 0 && *data != '\r') {
- data++;
- bleft--;
- }
-
- if (bleft < 2)
- goto too_short;
-
- if (data[0] != '\r' || data[1] != '\n')
- goto not_cookie;
-
- smp->data.str.len = (char *)data - smp->data.str.str;
- smp->flags = SMP_F_VOLATILE;
- return 1;
-
- too_short:
- smp->flags = SMP_F_MAY_CHANGE;
- not_cookie:
- return 0;
-}
-
-/************************************************************************/
-/* All supported ACL keywords must be declared here. */
-/************************************************************************/
-
-/* returns either 1 or 0 depending on whether an RDP cookie is found or not */
-static int
-acl_fetch_rdp_cookie_cnt(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
- const struct arg *args, struct sample *smp)
-{
- int ret;
-
- ret = smp_fetch_rdp_cookie(px, l4, l7, opt, args, smp);
-
- if (smp->flags & SMP_F_MAY_CHANGE)
- return 0;
-
- smp->flags = SMP_F_VOLATILE;
- smp->type = SMP_T_UINT;
- smp->data.uint = ret;
- return 1;
-}
-
-
/* fetch the connection's source IPv4/IPv6 address */
static int
smp_fetch_src(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
@@ -1594,142 +1478,8 @@
smp->flags = 0;
return 1;
-}
-
-static int
-smp_fetch_payload_lv(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
- const struct arg *arg_p, struct sample *smp)
-{
- unsigned int len_offset = arg_p[0].data.uint;
- unsigned int len_size = arg_p[1].data.uint;
- unsigned int buf_offset;
- unsigned int buf_size = 0;
- struct channel *chn;
- int i;
-
- /* Format is (len offset, len size, buf offset) or (len offset, len size) */
- /* by default buf offset == len offset + len size */
- /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
-
- if (!l4)
- return 0;
-
- chn = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? l4->rep : l4->req;
-
- if (!chn)
- return 0;
-
- if (len_offset + len_size > chn->buf->i)
- goto too_short;
-
- for (i = 0; i < len_size; i++) {
- buf_size = (buf_size << 8) + ((unsigned char *)chn->buf->p)[i + len_offset];
- }
-
- /* 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_size || buf_size > chn->buf->size || buf_offset + buf_size > chn->buf->size) {
- /* will never match */
- smp->flags = 0;
- return 0;
- }
-
- if (buf_offset + buf_size > chn->buf->i)
- goto too_short;
-
- /* init chunk as read only */
- smp->type = SMP_T_CBIN;
- chunk_initlen(&smp->data.str, chn->buf->p + buf_offset, 0, buf_size);
- smp->flags = SMP_F_VOLATILE;
- return 1;
-
- too_short:
- smp->flags = SMP_F_MAY_CHANGE;
- return 0;
}
-static int
-smp_fetch_payload(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
- const struct arg *arg_p, struct sample *smp)
-{
- unsigned int buf_offset = arg_p[0].data.uint;
- unsigned int buf_size = arg_p[1].data.uint;
- struct channel *chn;
-
- if (!l4)
- return 0;
-
- chn = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? l4->rep : l4->req;
-
- if (!chn)
- return 0;
-
- if (!buf_size || buf_size > chn->buf->size || buf_offset + buf_size > chn->buf->size) {
- /* will never match */
- smp->flags = 0;
- return 0;
- }
-
- if (buf_offset + buf_size > chn->buf->i)
- goto too_short;
-
- /* init chunk as read only */
- smp->type = SMP_T_CBIN;
- chunk_initlen(&smp->data.str, chn->buf->p + buf_offset, 0, buf_size);
- smp->flags = SMP_F_VOLATILE;
- return 1;
-
- too_short:
- smp->flags = SMP_F_MAY_CHANGE;
- return 0;
-}
-
-/* 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) {
- 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) {
- 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) {
- memprintf(err_msg, "payload offset too negative");
- return 0;
- }
- return 1;
-}
-
#ifdef IPV6_V6ONLY
/* parse the "v4v6" bind keyword */
static int bind_parse_v4v6(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
@@ -1852,40 +1602,35 @@
#endif
static struct cfg_kw_list cfg_kws = {{ },{
- { CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
+ { CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
{ CFG_LISTEN, "tcp-response", tcp_parse_tcp_rep },
{ 0, NULL, NULL },
}};
+
/* Note: must not be declared <const> as its list will be overwritten.
* Please take care of keeping this list alphabetically sorted.
*/
static struct acl_kw_list acl_kws = {{ },{
- { "dst", acl_parse_ip, smp_fetch_dst, acl_match_ip, ACL_USE_TCP4_PERMANENT, 0 },
- { "dst_port", acl_parse_int, smp_fetch_dport, acl_match_int, ACL_USE_TCP_PERMANENT, 0 },
- { "payload", acl_parse_str, smp_fetch_payload, acl_match_str, ACL_USE_L6REQ_VOLATILE, ARG2(2,UINT,UINT), val_payload },
- { "payload_lv", acl_parse_str, smp_fetch_payload_lv, acl_match_str, ACL_USE_L6REQ_VOLATILE, ARG3(2,UINT,UINT,SINT), val_payload_lv },
- { "req_rdp_cookie", acl_parse_str, smp_fetch_rdp_cookie, acl_match_str, ACL_USE_L6REQ_VOLATILE, ARG1(0,STR) },
- { "req_rdp_cookie_cnt", acl_parse_int, acl_fetch_rdp_cookie_cnt, acl_match_int, ACL_USE_L6REQ_VOLATILE, ARG1(0,STR) },
- { "src", acl_parse_ip, smp_fetch_src, acl_match_ip, ACL_USE_TCP4_PERMANENT, 0 },
- { "src_port", acl_parse_int, smp_fetch_sport, acl_match_int, ACL_USE_TCP_PERMANENT, 0 },
- { NULL, NULL, NULL, NULL },
+ { "dst", acl_parse_ip, smp_fetch_dst, acl_match_ip, ACL_USE_TCP4_PERMANENT, 0 },
+ { "dst_port", acl_parse_int, smp_fetch_dport, acl_match_int, ACL_USE_TCP_PERMANENT, 0 },
+ { "src", acl_parse_ip, smp_fetch_src, acl_match_ip, ACL_USE_TCP4_PERMANENT, 0 },
+ { "src_port", acl_parse_int, smp_fetch_sport, acl_match_int, ACL_USE_TCP_PERMANENT, 0 },
+ { /* END */ },
}};
+
/* Note: must not be declared <const> as its list will be overwritten.
* Note: fetches that may return multiple types must be declared as the lowest
* common denominator, the type that can be casted into all other ones. For
* instance v4/v6 must be declared v4.
*/
static struct sample_fetch_kw_list sample_fetch_keywords = {{ },{
- { "dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
- { "dst_port", smp_fetch_dport, 0, NULL, SMP_T_UINT, SMP_USE_L4CLI },
- { "payload", smp_fetch_payload, ARG2(2,UINT,UINT), val_payload, SMP_T_CBIN, SMP_USE_L6REQ|SMP_USE_L6RES },
- { "payload_lv", smp_fetch_payload_lv, ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_CBIN, SMP_USE_L6REQ|SMP_USE_L6RES },
- { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(1,STR), NULL, SMP_T_CSTR, SMP_USE_L6REQ },
- { "src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
- { "src_port", smp_fetch_sport, 0, NULL, SMP_T_UINT, SMP_USE_L4CLI },
- { NULL, NULL, 0, 0, 0 },
+ { "dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
+ { "dst_port", smp_fetch_dport, 0, NULL, SMP_T_UINT, SMP_USE_L4CLI },
+ { "src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
+ { "src_port", smp_fetch_sport, 0, NULL, SMP_T_UINT, SMP_USE_L4CLI },
+ { /* END */ },
}};
/************************************************************************/