From: Willy Tarreau Date: Mon, 23 Apr 2012 21:13:20 +0000 (+0200) Subject: MEDIUM: acl/pattern: switch rdp_cookie functions stack up-down X-Git-Tag: v1.5-dev9~43 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=32389b7d042f0dfe7e1b11a3f9e3678a6ea226df;p=thirdparty%2Fhaproxy.git 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 998ac43620..131d799858 100644 --- a/include/proto/acl.h +++ b/include/proto/acl.h @@ -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); diff --git a/include/proto/backend.h b/include/proto/backend.h index c8322b8eba..b4dfc835c3 100644 --- a/include/proto/backend.h +++ b/include/proto/backend.h @@ -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); diff --git a/include/proto/proto_tcp.h b/include/proto/proto_tcp.h index 1665f151f5..91573e9596 100644 --- a/include/proto/proto_tcp.h +++ b/include/proto/proto_tcp.h @@ -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 diff --git a/src/acl.c b/src/acl.c index 5d86a3e1a1..36b53070c3 100644 --- a/src/acl.c +++ b/src/acl.c @@ -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 }, diff --git a/src/backend.c b/src/backend.c index fc8f22fa2d..c0c2412679 100644 --- a/src/backend.c +++ b/src/backend.c @@ -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; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index bd46de29c0..317a5f37a1 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -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 },