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.
This commit is contained in:
Willy Tarreau 2012-04-23 23:13:20 +02:00
parent b8c8f1f611
commit 32389b7d04
6 changed files with 142 additions and 157 deletions

View File

@ -177,10 +177,6 @@ int acl_fetch_nothing(struct proxy *px, struct session *l4, void *l7, int dir,
/* 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);

View File

@ -37,6 +37,7 @@ int srv_redispatch_connect(struct session *t);
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);

View File

@ -33,8 +33,8 @@ void tcpv6_add_listener(struct listener *listener);
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

114
src/acl.c
View File

@ -453,118 +453,6 @@ acl_fetch_ssl_hello_sni(struct proxy *px, struct session *l4, void *l7, int dir,
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 @@ static struct acl_kw_list acl_kws = {{ },{
{ "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 },

View File

@ -402,7 +402,6 @@ struct server *get_server_rch(struct session *s)
unsigned long len;
const char *p;
int ret;
struct acl_expr expr;
struct sample smp;
struct arg args[2];
@ -410,7 +409,6 @@ struct server *get_server_rch(struct session *s)
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 @@ struct server *get_server_rch(struct session *s)
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 @@ int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit)
{
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 @@ int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit)
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 @@ int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit)
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;

View File

@ -1247,10 +1247,146 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
}
/************************************************************************/
/* 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,
@ -1472,34 +1608,6 @@ pattern_fetch_payload(struct proxy *px, struct session *l4, void *l7, int dir,
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;
}
/* 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
@ -1556,6 +1664,8 @@ static struct cfg_kw_list cfg_kws = {{ },{
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 },