CLEANUP: tree-wide: define and use acl_match_cond() helper

acl_match_cond() combines acl_exec_cond() + acl_pass() and a check on the
condition->pol (to check if the cond is inverted) in order to return
either 0 if the cond doesn't match or 1 if it matches (or NULL).

Thanks to this we can actually simplify some redundant constructs that
iterate over rules and evaluate if the condition matches or not.

Conditions for tcp-request inspect-content and tcp-response
inspect-content couldn't be simplified because they perform an extra
check for missing data, and thus still need to leverage acl_exec_cond()

It's best to display the patch using "-w", like "git show xxxx -w",
because some blocks had to be re-indented after the cleanup, which
makes the patch hard to review by default.
This commit is contained in:
Aurelien DARRAGON 2025-01-22 14:15:47 +01:00
parent 94d3b7375a
commit e768a531b7
7 changed files with 354 additions and 462 deletions

View File

@ -104,6 +104,26 @@ struct acl_cond *build_acl_cond(const char *file, int line, struct list *known_a
*/
enum acl_test_res acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *sess, struct stream *strm, unsigned int opt);
/* helper that combines acl_exec_cond() and acl_pass(), and also takes into
* account cond->pol in order to return either 1 if the cond should pass and
* 0 otherwise
* <cond> may be NULL, in which case 1 is returned as the cond cannot fail
*/
static inline int acl_match_cond(struct acl_cond *cond, struct proxy *px, struct session *sess, struct stream *strm, unsigned int opt)
{
int ret;
if (!cond)
return 1;
ret = acl_pass(acl_exec_cond(cond, px, sess, strm, opt));
if (cond->pol == ACL_COND_UNLESS)
ret = !ret;
return ret;
}
/* Returns a pointer to the first ACL conflicting with usage at place <where>
* which is one of the SMP_VAL_* bits indicating a check place, or NULL if
* no conflict is found. Only full conflicts are detected (ACL is not usable).

View File

@ -311,7 +311,6 @@ static int fcgi_flt_http_headers(struct stream *s, struct filter *filter, struct
struct eb_root hdr_rules = EB_ROOT;
struct htx *htx;
struct http_hdr_ctx ctx;
int ret;
htx = htxbuf(&msg->chn->buf);
@ -368,16 +367,8 @@ static int fcgi_flt_http_headers(struct stream *s, struct filter *filter, struct
goto end;
list_for_each_entry(rule, &fcgi_conf->param_rules, list) {
if (rule->cond) {
ret = acl_exec_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
/* the rule does not match */
if (!ret)
if (!acl_match_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
}
param_rule = NULL;
node = ebis_lookup_len(&param_rules, rule->name.ptr, rule->name.len);
@ -398,16 +389,8 @@ static int fcgi_flt_http_headers(struct stream *s, struct filter *filter, struct
}
list_for_each_entry(rule, &fcgi_conf->hdr_rules, list) {
if (rule->cond) {
ret = acl_exec_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
/* the rule does not match */
if (!ret)
if (!acl_match_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
}
hdr_rule = NULL;
node = ebis_lookup_len(&hdr_rules, rule->name.ptr, rule->name.len);

View File

@ -592,16 +592,8 @@ static int spoe_encode_message(struct stream *s, struct spoe_context *ctx,
struct spoe_arg *arg;
int ret;
if (msg->cond) {
ret = acl_exec_cond(msg->cond, s->be, s->sess, s, dir|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (msg->cond->pol == ACL_COND_UNLESS)
ret = !ret;
/* the rule does not match */
if (!ret)
if (!acl_match_cond(msg->cond, s->be, s->sess, s, dir|SMP_OPT_FINAL))
goto next;
}
/* Check if there is enough space for the message name and the
* number of arguments. It implies <msg->id_len> is encoded on 2

View File

@ -237,20 +237,15 @@ int http_wait_for_request(struct stream *s, struct channel *req, int an_bit)
/* Check if we want to fail this monitor request or not */
list_for_each_entry(cond, &sess->fe->mon_fail_cond, list) {
int ret = acl_exec_cond(cond, sess->fe, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
if (!acl_match_cond(cond, sess->fe, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
ret = acl_pass(ret);
if (cond->pol == ACL_COND_UNLESS)
ret = !ret;
if (ret) {
/* we fail this request, let's return 503 service unavail */
txn->status = 503;
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_LOCAL; /* we don't want a real error here */
goto return_prx_cond;
}
}
/* nothing to fail, let's reply normally */
txn->status = 200;
@ -505,16 +500,8 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s
/* check whether we have some ACLs set to redirect this request */
list_for_each_entry(rule, &px->redirect_rules, list) {
if (rule->cond) {
int ret;
ret = acl_exec_cond(rule->cond, px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
if (!ret)
if (!acl_match_cond(rule->cond, px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
}
if (!http_apply_redirect_rule(rule, s, txn)) {
goto return_int_err;
}
@ -2757,18 +2744,8 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
list_for_each_entry(rule, s->current_rule_list, list) {
/* check optional condition */
if (rule->cond) {
int ret;
ret = acl_exec_cond(rule->cond, px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
if (!ret) /* condition not matched */
if (!acl_match_cond(rule->cond, px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
}
act_opts |= ACT_OPT_FIRST;
resume_execution:
@ -2938,18 +2915,8 @@ static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct lis
list_for_each_entry(rule, s->current_rule_list, list) {
/* check optional condition */
if (rule->cond) {
int ret;
ret = acl_exec_cond(rule->cond, px, sess, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
if (!ret) /* condition not matched */
if (!acl_match_cond(rule->cond, px, sess, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL))
continue;
}
act_opts |= ACT_OPT_FIRST;
resume_execution:
@ -4122,21 +4089,13 @@ static int http_handle_stats(struct stream *s, struct channel *req, struct proxy
/* now check whether we have some admin rules for this request */
list_for_each_entry(stats_admin_rule, &uri_auth->admin_rules, list) {
int ret = 1;
if (!acl_match_cond(stats_admin_rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
if (stats_admin_rule->cond) {
ret = acl_exec_cond(stats_admin_rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (stats_admin_rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
}
if (ret) {
/* no rule, or the rule matches */
ctx->flags |= STAT_F_ADMIN;
break;
}
}
if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
appctx->st0 = STAT_HTTP_HEAD;

View File

@ -18,7 +18,6 @@ int quic_init_exec_rules(struct listener *li, struct quic_dgram *dgram)
{
static THREAD_LOCAL struct session rule_sess;
struct act_rule *rule;
enum acl_test_res ret;
struct proxy *px;
int result = 1;
@ -34,16 +33,9 @@ int quic_init_exec_rules(struct listener *li, struct quic_dgram *dgram)
rule_sess.origin = &dgram->obj_type;
list_for_each_entry(rule, &px->quic_init_rules, list) {
ret = ACL_TEST_PASS;
if (!acl_match_cond(rule->cond, px, &rule_sess, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
if (rule->cond) {
ret = acl_exec_cond(rule->cond, px, &rule_sess, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
}
if (ret) {
if (rule->action_ptr) {
switch (rule->action_ptr(rule, px, &rule_sess, NULL, 0)) {
case ACT_RET_CONT:
@ -69,7 +61,6 @@ int quic_init_exec_rules(struct listener *li, struct quic_dgram *dgram)
goto end;
}
}
}
end:
return result;

View File

@ -1072,21 +1072,15 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an
struct switching_rule *rule;
list_for_each_entry(rule, &fe->switching_rules, list) {
int ret = 1;
struct proxy *backend = NULL;
if (rule->cond) {
ret = acl_exec_cond(rule->cond, fe, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
}
if (!acl_match_cond(rule->cond, fe, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
if (ret) {
/* If the backend name is dynamic, try to resolve the name.
* If we can't resolve the name, or if any error occurs, break
* the loop and fallback to the default backend.
*/
struct proxy *backend = NULL;
if (rule->dynamic) {
struct buffer *tmp;
@ -1111,7 +1105,6 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an
goto sw_failed;
break;
}
}
/* To ensure correct connection accounting on the backend, we
* have to assign one if it was not set (eg: a listen). This
@ -1147,16 +1140,9 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an
* persistence rule, and report that in the stream.
*/
list_for_each_entry(prst_rule, &s->be->persist_rules, list) {
int ret = 1;
if (!acl_match_cond(prst_rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
if (prst_rule->cond) {
ret = acl_exec_cond(prst_rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (prst_rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
}
if (ret) {
/* no rule, or the rule matches */
if (prst_rule->type == PERSIST_TYPE_FORCE) {
s->flags |= SF_FORCE_PRST;
@ -1165,7 +1151,6 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an
}
break;
}
}
DBG_TRACE_LEAVE(STRM_EV_STRM_ANA, s);
return 1;
@ -1201,16 +1186,11 @@ static int process_server_rules(struct stream *s, struct channel *req, int an_bi
if (!(s->flags & SF_ASSIGNED)) {
list_for_each_entry(rule, &px->server_rules, list) {
int ret;
ret = acl_exec_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
if (ret) {
struct server *srv;
if (!acl_match_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
if (rule->dynamic) {
struct buffer *tmp = get_trash_chunk();
@ -1236,7 +1216,6 @@ static int process_server_rules(struct stream *s, struct channel *req, int an_bi
*/
}
}
}
req->analysers &= ~an_bit;
req->analyse_exp = TICK_ETERNITY;
@ -1310,7 +1289,7 @@ static int process_sticking_rules(struct stream *s, struct channel *req, int an_
DBG_TRACE_ENTER(STRM_EV_STRM_ANA, s);
list_for_each_entry(rule, &px->sticking_rules, list) {
int ret = 1 ;
struct stktable_key *key;
int i;
/* Only the first stick store-request of each table is applied
@ -1330,15 +1309,8 @@ static int process_sticking_rules(struct stream *s, struct channel *req, int an_
continue;
}
if (rule->cond) {
ret = acl_exec_cond(rule->cond, px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
}
if (ret) {
struct stktable_key *key;
if (!acl_match_cond(rule->cond, px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
key = stktable_fetch_key(rule->table.t, px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->expr, NULL);
if (!key)
@ -1365,7 +1337,6 @@ static int process_sticking_rules(struct stream *s, struct channel *req, int an_
}
}
}
}
req->analysers &= ~an_bit;
req->analyse_exp = TICK_ETERNITY;
@ -1388,7 +1359,7 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit
DBG_TRACE_ENTER(STRM_EV_STRM_ANA, s);
list_for_each_entry(rule, &px->storersp_rules, list) {
int ret = 1 ;
struct stktable_key *key;
/* Only the first stick store-response of each table is applied
* and other ones are ignored. The purpose is to allow complex
@ -1411,15 +1382,8 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit
if (i < s->store_count)
continue;
if (rule->cond) {
ret = acl_exec_cond(rule->cond, px, sess, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
}
if (ret) {
struct stktable_key *key;
if (!acl_match_cond(rule->cond, px, sess, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL))
continue;
key = stktable_fetch_key(rule->table.t, px, sess, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL, rule->expr, NULL);
if (!key)
@ -1435,7 +1399,6 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit
}
}
}
}
/* process store request and store response */
for (i = 0; i < s->store_count; i++) {

View File

@ -158,9 +158,11 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit)
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
if (!ret)
continue;
}
if (ret) {
act_opts |= ACT_OPT_FIRST;
resume_execution:
/* Always call the action function if defined */
@ -218,7 +220,6 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit)
goto deny;
}
}
}
if (def_rules && s->current_rule_list == def_rules) {
s->current_rule_list = rules;
@ -348,9 +349,10 @@ int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit)
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
if (!ret)
continue;
}
if (ret) {
act_opts |= ACT_OPT_FIRST;
resume_execution:
@ -419,7 +421,6 @@ int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit)
goto end;
}
}
}
if (def_rules && s->current_rule_list == def_rules) {
s->current_rule_list = rules;
@ -498,7 +499,6 @@ int tcp_exec_l4_rules(struct session *sess)
struct act_rule *rule;
struct connection *conn = objt_conn(sess->origin);
int result = 1;
enum acl_test_res ret;
if (!conn)
return result;
@ -508,16 +508,10 @@ int tcp_exec_l4_rules(struct session *sess)
restart:
list_for_each_entry(rule, &px->tcp_req.l4_rules, list) {
ret = ACL_TEST_PASS;
if (rule->cond) {
ret = acl_exec_cond(rule->cond, sess->fe, sess, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
}
if (!acl_match_cond(rule->cond, sess->fe, sess, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
if (ret) {
/* Always call the action function if defined */
if (rule->action_ptr) {
switch (rule->action_ptr(rule, sess->fe, sess, NULL, ACT_OPT_FINAL | ACT_OPT_FIRST)) {
@ -574,7 +568,6 @@ int tcp_exec_l4_rules(struct session *sess)
conn->flags |= CO_FL_ACCEPT_CIP;
}
}
}
if (px != sess->fe) {
px = sess->fe;
@ -596,23 +589,15 @@ int tcp_exec_l5_rules(struct session *sess)
struct proxy *px = sess->fe;
struct act_rule *rule;
int result = 1;
enum acl_test_res ret;
if (sess->fe->defpx && (sess->fe->mode == PR_MODE_TCP || sess->fe->mode == PR_MODE_HTTP))
px = sess->fe->defpx;
restart:
list_for_each_entry(rule, &px->tcp_req.l5_rules, list) {
ret = ACL_TEST_PASS;
if (!acl_match_cond(rule->cond, sess->fe, sess, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
continue;
if (rule->cond) {
ret = acl_exec_cond(rule->cond, sess->fe, sess, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
ret = !ret;
}
if (ret) {
/* Always call the action function if defined */
if (rule->action_ptr) {
switch (rule->action_ptr(rule, sess->fe, sess, NULL, ACT_OPT_FINAL | ACT_OPT_FIRST)) {
@ -651,7 +636,6 @@ int tcp_exec_l5_rules(struct session *sess)
goto end;
}
}
}
if (px != sess->fe) {
px = sess->fe;