MEDIUM: acl/pattern: switch rdp_cookie functions stack up-down
Previously, both pattern, backend and persist_rdp_cookie would build fake
ACL expressions to fetch an RDP cookie by calling acl_fetch_rdp_cookie().
Now we switch roles. The RDP cookie fetch function is provided as a sample
fetch function that all others rely on, including ACL. The code is exactly
the same, only the args handling moved from expr->args to args. The code
was moved to proto_tcp.c, but probably that a dedicated file would be more
suited to content handling.
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index bd46de2..317a5f3 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1248,9 +1248,145 @@
/************************************************************************/
+/* All supported sample fetch functios 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 patterns. 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, int dir,
+ 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->i;
+ if (bleft <= 11)
+ goto too_short;
+
+ data = (const unsigned char *)l4->req->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;
+}
+
+static int
+pattern_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
+ const struct arg *arg_p, struct sample *smp)
+{
+ int ret;
+
+ /* sample type set by smp_fetch_rdp_cookie() */
+ ret = smp_fetch_rdp_cookie(px, l4, NULL, ACL_DIR_REQ, arg_p, smp);
+ if (ret == 0 || (smp->flags & SMP_F_MAY_CHANGE) || smp->data.str.len == 0)
+ return 0;
+ return 1;
+}
+
+/************************************************************************/
/* All supported ACL keywords must be declared here. */
/************************************************************************/
+static int
+acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
+ struct acl_expr *expr, struct sample *smp)
+{
+ return smp_fetch_rdp_cookie(px, l4, l7, dir, expr->args, smp);
+}
+
+/* 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, int dir,
+ struct acl_expr *expr, struct sample *smp)
+{
+ int ret;
+
+ ret = smp_fetch_rdp_cookie(px, l4, l7, dir, expr->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;
+}
+
+
/* copy the source IPv4/v6 address into temp_pattern */
static int
acl_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir,
@@ -1469,34 +1605,6 @@
smp->type = SMP_T_CBIN;
chunk_initlen(&smp->data.str, b->p + buf_offset, 0, buf_size);
- return 1;
-}
-
-static int
-pattern_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
- const struct arg *arg_p, struct sample *smp)
-{
- int ret;
- struct acl_expr expr;
- struct arg args[2];
-
- if (!l4)
- return 0;
-
- memset(&expr, 0, sizeof(expr));
- memset(smp, 0, sizeof(*smp));
-
- args[0].type = ARGT_STR;
- args[0].data.str.str = arg_p[0].data.str.str;
- args[0].data.str.len = arg_p[0].data.str.len;
- args[1].type = ARGT_STOP;
-
- expr.args = args;
-
- /* type set by acl_fetch_rdp_cookie */
- ret = acl_fetch_rdp_cookie(px, l4, NULL, ACL_DIR_REQ, &expr, smp);
- if (ret == 0 || (smp->flags & SMP_F_MAY_CHANGE) || smp->data.str.len == 0)
- return 0;
return 1;
}
@@ -1556,6 +1664,8 @@
static struct acl_kw_list acl_kws = {{ },{
{ "dst", acl_parse_ip, acl_fetch_dst, acl_match_ip, ACL_USE_TCP4_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "dst_port", acl_parse_int, acl_fetch_dport, acl_match_int, ACL_USE_TCP_PERMANENT, 0 },
+ { "req_rdp_cookie", acl_parse_str, acl_fetch_rdp_cookie, acl_match_str, ACL_USE_L6REQ_VOLATILE|ACL_MAY_LOOKUP, 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, acl_fetch_src, acl_match_ip, ACL_USE_TCP4_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "src_port", acl_parse_int, acl_fetch_sport, acl_match_int, ACL_USE_TCP_PERMANENT, 0 },
{ NULL, NULL, NULL, NULL },