diff --git a/include/types/proxy.h b/include/types/proxy.h index 6a96f94b9..c403e59f4 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -84,6 +84,7 @@ struct proxy { char *name; /* default backend name during config parse */ } defbe; struct list acl; /* ACL declared on this proxy */ + struct list block_cond; /* early blocking conditions (chained) */ struct server *srv; /* known servers */ int srv_act, srv_bck; /* # of running servers */ int tot_wact, tot_wbck; /* total weights of active and backup servers */ diff --git a/src/cfgparse.c b/src/cfgparse.c index c4c6c8c27..41d706611 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -494,6 +494,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args) proxy = curproxy; LIST_INIT(&curproxy->pendconns); LIST_INIT(&curproxy->acl); + LIST_INIT(&curproxy->block_cond); curproxy->id = strdup(args[1]); curproxy->cap = rc; @@ -912,6 +913,28 @@ int cfg_parse_listen(const char *file, int linenum, char **args) } curproxy->conn_retries = atol(args[1]); } + else if (!strcmp(args[0], "block")) { /* early blocking based on ACLs */ + int pol = ACL_COND_NONE; + struct acl_cond *cond; + + if (!strcmp(args[1], "if")) + pol = ACL_COND_IF; + else if (!strcmp(args[1], "unless")) + pol = ACL_COND_UNLESS; + + if (pol == ACL_COND_NONE) { + Alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n", + file, linenum, args[0]); + return -1; + } + + if ((cond = parse_acl_cond((const char **)args + 2, &curproxy->acl, pol)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing blocking condition.\n", + file, linenum); + return -1; + } + LIST_ADDQ(&curproxy->block_cond, &cond->list); + } else if (!strcmp(args[0], "stats")) { if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) return 0; diff --git a/src/proto_http.c b/src/proto_http.c index 706ef4640..6d4c15280 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -1674,9 +1674,25 @@ int process_cli(struct session *t) */ do { + struct acl_cond *cond; struct proxy *rule_set = t->be; cur_proxy = t->be; + /* first check whether we have some ACLs set to block this request */ + list_for_each_entry(cond, &cur_proxy->block_cond, list) { + int ret = acl_exec_cond(cond, cur_proxy, t, txn); + if (cond->pol == ACL_COND_UNLESS) + ret = !ret; + + if (ret) { + txn->status = 403; + /* let's log the request time */ + t->logs.t_request = tv_ms_elapsed(&t->logs.tv_accept, &now); + client_retnclose(t, error_message(t, HTTP_ERR_403)); + goto return_prx_cond; + } + } + /* try headers filters */ if (rule_set->req_exp != NULL) { if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)