From: Willy Tarreau Date: Thu, 19 Apr 2012 21:35:54 +0000 (+0200) Subject: MAJOR: acl: ensure that implicit table and proxies are valid X-Git-Tag: v1.5-dev9~60 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc2c1fd44907b2977c82bc71275bc484824f9a0b;p=thirdparty%2Fhaproxy.git MAJOR: acl: ensure that implicit table and proxies are valid A large number of ACLs make use of frontend, backend or table names in their arguments, and fall back to the current proxy when no argument is passed. If the expected capability is not available, the ACL silently fails at runtime. Now we make all those names mandatory in the parser and we rely on acl_find_targets() to replace the missing names with the holding proxy, then to perform the appropriate tests, and to reject errors at parsing time. It is possible that some faulty configurations will get rejected from now on, while they used to silently fail till now. This is the reason why this change is marked as MAJOR. --- diff --git a/src/acl.c b/src/acl.c index dc9925d519..025e4780a8 100644 --- a/src/acl.c +++ b/src/acl.c @@ -1396,6 +1396,26 @@ struct acl_expr *parse_acl_expr(const char **args) if (nbargs < 0) goto out_free_expr; } + else if (ARGM(aclkw->arg_mask) == 1) { + int type = (aclkw->arg_mask >> 4) & 15; + + /* If a proxy is noted as a mandatory argument, we'll fake + * an empty one so that acl_find_targets() resolves it as + * the current one later. + */ + if (type != ARGT_FE && type != ARGT_BE && type != ARGT_TAB) + goto out_free_expr; + + /* Build an arg list containing the type as an empty string + * and the usual STOP. + */ + expr->args = calloc(2, sizeof(*expr->args)); + expr->args[0].type = type; + expr->args[0].data.str.str = strdup(""); + expr->args[0].data.str.len = 1; + expr->args[0].data.str.len = 0; + expr->args[1].type = ARGT_STOP; + } else if (ARGM(aclkw->arg_mask)) { /* there were some mandatory arguments */ goto out_free_expr; @@ -2013,18 +2033,14 @@ acl_find_targets(struct proxy *p) expr->args->data.srv = srv; } else if (arg->type == ARGT_FE) { - struct proxy *prx; - char *pname; + struct proxy *prx = p; + char *pname = p->id; - if (!expr->args->data.str.len) { - Alert("proxy %s: acl '%s' %s(): missing frontend name.\n", - p->id, acl->name, expr->kw->kw); - cfgerr++; - continue; + if (expr->args->data.str.len) { + pname = expr->args->data.str.str; + prx = findproxy(pname, PR_CAP_FE); } - pname = expr->args->data.str.str; - prx = findproxy(pname, PR_CAP_FE); if (!prx) { Alert("proxy %s: acl '%s' %s(): unable to find frontend '%s'.\n", p->id, acl->name, expr->kw->kw, pname); @@ -2032,22 +2048,25 @@ acl_find_targets(struct proxy *p) continue; } + if (!(prx->cap & PR_CAP_FE)) { + Alert("proxy %s: acl '%s' %s(): proxy '%s' has no frontend capability.\n", + p->id, acl->name, expr->kw->kw, pname); + cfgerr++; + continue; + } + free(expr->args->data.str.str); expr->args->data.prx = prx; } else if (arg->type == ARGT_BE) { - struct proxy *prx; - char *pname; + struct proxy *prx = p; + char *pname = p->id; - if (!expr->args->data.str.len) { - Alert("proxy %s: acl '%s' %s(): missing backend name.\n", - p->id, acl->name, expr->kw->kw); - cfgerr++; - continue; + if (expr->args->data.str.len) { + pname = expr->args->data.str.str; + prx = findproxy(pname, PR_CAP_BE); } - pname = expr->args->data.str.str; - prx = findproxy(pname, PR_CAP_BE); if (!prx) { Alert("proxy %s: acl '%s' %s(): unable to find backend '%s'.\n", p->id, acl->name, expr->kw->kw, pname); @@ -2055,22 +2074,25 @@ acl_find_targets(struct proxy *p) continue; } + if (!(prx->cap & PR_CAP_BE)) { + Alert("proxy %s: acl '%s' %s(): proxy '%s' has no backend capability.\n", + p->id, acl->name, expr->kw->kw, pname); + cfgerr++; + continue; + } + free(expr->args->data.str.str); expr->args->data.prx = prx; } else if (arg->type == ARGT_TAB) { - struct proxy *prx; - char *pname; + struct proxy *prx = p; + char *pname = p->id; - if (!expr->args->data.str.len) { - Alert("proxy %s: acl '%s' %s(): missing table name.\n", - p->id, acl->name, expr->kw->kw); - cfgerr++; - continue; + if (expr->args->data.str.len) { + pname = expr->args->data.str.str; + prx = find_stktable(pname); } - pname = expr->args->data.str.str; - prx = find_stktable(pname); if (!prx) { Alert("proxy %s: acl '%s' %s(): unable to find table '%s'.\n", p->id, acl->name, expr->kw->kw, pname); @@ -2078,6 +2100,14 @@ acl_find_targets(struct proxy *p) continue; } + + if (!prx->table.size) { + Alert("proxy %s: acl '%s' %s(): no table in proxy '%s'.\n", + p->id, acl->name, expr->kw->kw, pname); + cfgerr++; + continue; + } + free(expr->args->data.str.str); expr->args->data.prx = prx; } diff --git a/src/backend.c b/src/backend.c index fd2528f4a7..b0d7c39b1b 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1578,13 +1578,13 @@ acl_fetch_srv_conn(struct proxy *px, struct session *l4, void *l7, int dir, * Please take care of keeping this list alphabetically sorted. */ static struct acl_kw_list acl_kws = {{ },{ - { "avg_queue", acl_parse_int, acl_fetch_avg_queue_size, acl_match_int, ACL_USE_NOTHING, ARG1(0,BE) }, - { "be_conn", acl_parse_int, acl_fetch_be_conn, acl_match_int, ACL_USE_NOTHING, ARG1(0,BE) }, + { "avg_queue", acl_parse_int, acl_fetch_avg_queue_size, acl_match_int, ACL_USE_NOTHING, ARG1(1,BE) }, + { "be_conn", acl_parse_int, acl_fetch_be_conn, acl_match_int, ACL_USE_NOTHING, ARG1(1,BE) }, { "be_id", acl_parse_int, acl_fetch_be_id, acl_match_int, ACL_USE_NOTHING, 0 }, - { "be_sess_rate", acl_parse_int, acl_fetch_be_sess_rate, acl_match_int, ACL_USE_NOTHING, ARG1(0,BE) }, - { "connslots", acl_parse_int, acl_fetch_connslots, acl_match_int, ACL_USE_NOTHING, ARG1(0,BE) }, - { "nbsrv", acl_parse_int, acl_fetch_nbsrv, acl_match_int, ACL_USE_NOTHING, ARG1(0,BE) }, - { "queue", acl_parse_int, acl_fetch_queue_size, acl_match_int, ACL_USE_NOTHING, ARG1(0,BE) }, + { "be_sess_rate", acl_parse_int, acl_fetch_be_sess_rate, acl_match_int, ACL_USE_NOTHING, ARG1(1,BE) }, + { "connslots", acl_parse_int, acl_fetch_connslots, acl_match_int, ACL_USE_NOTHING, ARG1(1,BE) }, + { "nbsrv", acl_parse_int, acl_fetch_nbsrv, acl_match_int, ACL_USE_NOTHING, ARG1(1,BE) }, + { "queue", acl_parse_int, acl_fetch_queue_size, acl_match_int, ACL_USE_NOTHING, ARG1(1,BE) }, { "srv_conn", acl_parse_int, acl_fetch_srv_conn, acl_match_int, ACL_USE_NOTHING, ARG1(1,SRV) }, { "srv_id", acl_parse_int, acl_fetch_srv_id, acl_match_int, ACL_USE_RTR_INTERNAL, 0 }, { "srv_is_up", acl_parse_nothing, acl_fetch_srv_is_up, acl_match_nothing, ACL_USE_NOTHING, ARG1(1,SRV) }, diff --git a/src/frontend.c b/src/frontend.c index ebe864bb98..9f8c3232f8 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -544,9 +544,9 @@ acl_fetch_fe_conn(struct proxy *px, struct session *l4, void *l7, int dir, * Please take care of keeping this list alphabetically sorted. */ static struct acl_kw_list acl_kws = {{ },{ - { "fe_conn", acl_parse_int, acl_fetch_fe_conn, acl_match_int, ACL_USE_NOTHING, ARG1(0,FE) }, + { "fe_conn", acl_parse_int, acl_fetch_fe_conn, acl_match_int, ACL_USE_NOTHING, ARG1(1,FE) }, { "fe_id", acl_parse_int, acl_fetch_fe_id, acl_match_int, ACL_USE_NOTHING, 0 }, - { "fe_sess_rate", acl_parse_int, acl_fetch_fe_sess_rate, acl_match_int, ACL_USE_NOTHING, ARG1(0,FE) }, + { "fe_sess_rate", acl_parse_int, acl_fetch_fe_sess_rate, acl_match_int, ACL_USE_NOTHING, ARG1(1,FE) }, { NULL, NULL, NULL, NULL }, }}; diff --git a/src/session.c b/src/session.c index 4c5671a751..999701479c 100644 --- a/src/session.c +++ b/src/session.c @@ -3372,25 +3372,25 @@ static struct acl_kw_list acl_kws = {{ },{ { "sc2_kbytes_out", acl_parse_int, acl_fetch_sc2_kbytes_out, acl_match_int, ACL_USE_TCP4_VOLATILE, 0 }, { "sc2_sess_cnt", acl_parse_int, acl_fetch_sc2_sess_cnt, acl_match_int, ACL_USE_NOTHING, 0 }, { "sc2_sess_rate", acl_parse_int, acl_fetch_sc2_sess_rate, acl_match_int, ACL_USE_NOTHING, 0 }, - { "src_bytes_in_rate", acl_parse_int, acl_fetch_src_bytes_in_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_bytes_out_rate", acl_parse_int, acl_fetch_src_bytes_out_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_clr_gpc0", acl_parse_int, acl_fetch_src_clr_gpc0, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_conn_cnt", acl_parse_int, acl_fetch_src_conn_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_conn_cur", acl_parse_int, acl_fetch_src_conn_cur, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_conn_rate", acl_parse_int, acl_fetch_src_conn_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_get_gpc0", acl_parse_int, acl_fetch_src_get_gpc0, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_http_err_cnt", acl_parse_int, acl_fetch_src_http_err_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_http_err_rate", acl_parse_int, acl_fetch_src_http_err_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_http_req_cnt", acl_parse_int, acl_fetch_src_http_req_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_http_req_rate", acl_parse_int, acl_fetch_src_http_req_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_inc_gpc0", acl_parse_int, acl_fetch_src_inc_gpc0, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_kbytes_in", acl_parse_int, acl_fetch_src_kbytes_in, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_kbytes_out", acl_parse_int, acl_fetch_src_kbytes_out, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_sess_cnt", acl_parse_int, acl_fetch_src_sess_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_sess_rate", acl_parse_int, acl_fetch_src_sess_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "src_updt_conn_cnt", acl_parse_int, acl_fetch_src_updt_conn_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(0,TAB) }, - { "table_avl", acl_parse_int, acl_fetch_table_avl, acl_match_int, ACL_USE_NOTHING, ARG1(0,TAB) }, - { "table_cnt", acl_parse_int, acl_fetch_table_cnt, acl_match_int, ACL_USE_NOTHING, ARG1(0,TAB) }, + { "src_bytes_in_rate", acl_parse_int, acl_fetch_src_bytes_in_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_bytes_out_rate", acl_parse_int, acl_fetch_src_bytes_out_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_clr_gpc0", acl_parse_int, acl_fetch_src_clr_gpc0, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_conn_cnt", acl_parse_int, acl_fetch_src_conn_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_conn_cur", acl_parse_int, acl_fetch_src_conn_cur, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_conn_rate", acl_parse_int, acl_fetch_src_conn_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_get_gpc0", acl_parse_int, acl_fetch_src_get_gpc0, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_http_err_cnt", acl_parse_int, acl_fetch_src_http_err_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_http_err_rate", acl_parse_int, acl_fetch_src_http_err_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_http_req_cnt", acl_parse_int, acl_fetch_src_http_req_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_http_req_rate", acl_parse_int, acl_fetch_src_http_req_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_inc_gpc0", acl_parse_int, acl_fetch_src_inc_gpc0, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_kbytes_in", acl_parse_int, acl_fetch_src_kbytes_in, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_kbytes_out", acl_parse_int, acl_fetch_src_kbytes_out, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_sess_cnt", acl_parse_int, acl_fetch_src_sess_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_sess_rate", acl_parse_int, acl_fetch_src_sess_rate, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "src_updt_conn_cnt", acl_parse_int, acl_fetch_src_updt_conn_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE, ARG1(1,TAB) }, + { "table_avl", acl_parse_int, acl_fetch_table_avl, acl_match_int, ACL_USE_NOTHING, ARG1(1,TAB) }, + { "table_cnt", acl_parse_int, acl_fetch_table_cnt, acl_match_int, ACL_USE_NOTHING, ARG1(1,TAB) }, { NULL, NULL, NULL, NULL }, }};