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/include/proto/acl.h b/include/proto/acl.h
index 998ac43..131d799 100644
--- a/include/proto/acl.h
+++ b/include/proto/acl.h
@@ -177,10 +177,6 @@
/* always return false */
int acl_match_nothing(struct sample *smp, struct acl_pattern *pattern);
-/* Fetch the RDP cookie identified in the expression. */
-int acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
- struct acl_expr *expr, struct sample *smp);
-
/* Checks that the pattern matches the end of the tested string. */
int acl_match_end(struct sample *smp, struct acl_pattern *pattern);
diff --git a/include/proto/backend.h b/include/proto/backend.h
index c8322b8..b4dfc83 100644
--- a/include/proto/backend.h
+++ b/include/proto/backend.h
@@ -37,6 +37,7 @@
const char *backend_lb_algo_str(int algo);
int backend_parse_balance(const char **args, char *err,
int errlen, struct proxy *curproxy);
+int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit);
int be_downtime(struct proxy *px);
void recount_servers(struct proxy *px);
diff --git a/include/proto/proto_tcp.h b/include/proto/proto_tcp.h
index 1665f15..91573e9 100644
--- a/include/proto/proto_tcp.h
+++ b/include/proto/proto_tcp.h
@@ -33,8 +33,8 @@
int tcp_connect_server(struct stream_interface *si);
int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit);
int tcp_inspect_response(struct session *s, struct buffer *rep, int an_bit);
-int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit);
int tcp_exec_req_rules(struct session *s);
+int smp_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir, const struct arg *args, struct sample *smp);
/* Converts the TCP source address to a stick_table key usable for table
* lookups. Returns either NULL if the source cannot be converted (eg: not
diff --git a/src/acl.c b/src/acl.c
index 5d86a3e..36b5307 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -453,118 +453,6 @@
return 0;
}
-/* Fetch the RDP cookie identified in the expression.
- * 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
-acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
- struct acl_expr *expr, 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 (expr->args) {
-
- if (bleft <= expr->args->data.str.len)
- goto too_short;
-
- if ((data[expr->args->data.str.len] != '=') ||
- strncasecmp(expr->args->data.str.str, (const char *)data, expr->args->data.str.len) != 0)
- goto not_cookie;
-
- data += expr->args->data.str.len + 1;
- bleft -= expr->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
-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 = acl_fetch_rdp_cookie(px, l4, l7, dir, expr, 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;
-}
-
-
/*
* These functions are exported and may be used by any other component.
*/
@@ -2159,8 +2047,6 @@
{ "always_true", acl_parse_nothing, acl_fetch_true, acl_match_nothing, ACL_USE_NOTHING, 0 },
{ "rep_ssl_hello_type", acl_parse_int, acl_fetch_ssl_hello_type, acl_match_int, ACL_USE_L6RTR_VOLATILE, 0 },
{ "req_len", acl_parse_int, acl_fetch_req_len, acl_match_int, ACL_USE_L6REQ_VOLATILE, 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) },
{ "req_ssl_hello_type", acl_parse_int, acl_fetch_ssl_hello_type, acl_match_int, ACL_USE_L6REQ_VOLATILE, 0 },
{ "req_ssl_sni", acl_parse_str, acl_fetch_ssl_hello_sni, acl_match_str, ACL_USE_L6REQ_VOLATILE|ACL_MAY_LOOKUP, 0 },
{ "req_ssl_ver", acl_parse_dotted_ver, acl_fetch_req_ssl_ver, acl_match_int, ACL_USE_L6REQ_VOLATILE, 0 },
diff --git a/src/backend.c b/src/backend.c
index fc8f22f..c0c2412 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -402,7 +402,6 @@
unsigned long len;
const char *p;
int ret;
- struct acl_expr expr;
struct sample smp;
struct arg args[2];
@@ -410,7 +409,6 @@
if (px->lbprm.tot_weight == 0)
return NULL;
- memset(&expr, 0, sizeof(expr));
memset(&smp, 0, sizeof(smp));
args[0].type = ARGT_STR;
@@ -418,9 +416,7 @@
args[0].data.str.len = px->hh_len;
args[1].type = ARGT_STOP;
- expr.args = args;
-
- ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &smp);
+ ret = smp_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, args, &smp);
len = smp.data.str.len;
if (ret == 0 || (smp.flags & SMP_F_MAY_CHANGE) || len == 0)
@@ -1113,7 +1109,6 @@
{
struct proxy *px = s->be;
int ret;
- struct acl_expr expr;
struct sample smp;
struct server *srv = px->srv;
struct sockaddr_in addr;
@@ -1132,7 +1127,6 @@
if (s->flags & SN_ASSIGNED)
goto no_cookie;
- memset(&expr, 0, sizeof(expr));
memset(&smp, 0, sizeof(smp));
args[0].type = ARGT_STR;
@@ -1140,9 +1134,7 @@
args[0].data.str.len = s->be->rdp_cookie_len;
args[1].type = ARGT_STOP;
- expr.args = args;
-
- ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &smp);
+ ret = smp_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, args, &smp);
if (ret == 0 || (smp.flags & SMP_F_MAY_CHANGE) || smp.data.str.len == 0)
goto no_cookie;
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 },