From 5368532099b8e8c2c6970df8a2d1463a7eaa72bc Mon Sep 17 00:00:00 2001
From: Krzysztof Piotr Oledzki <ole#ans.pl>
Date: Tue, 27 Jan 2009 16:47:15 +0100
Subject: [MEDIUM] access control (block) rework - rfc
Allow more advanced access control:
RFC quality patch.
TODO: documentation
--- include/proto/acl.h | 5 +++++ include/types/proxy.h | 7 ++++++- src/acl.c | 19 +++++++++++++++++++ src/cfgparse.c | 33 +++++++++++++++++++++++++++++---- src/haproxy.c | 8 +++++++- src/proto_http.c | 39 +++++++++++++++++++++++++-------------- 6 files changed, 91 insertions(+), 20 deletions(-) diff --git a/include/proto/acl.h b/include/proto/acl.h index fffce48..8ccc8f0 100644 --- a/include/proto/acl.h +++ b/include/proto/acl.hReceived on 2009/01/27 17:50
@@ -92,6 +92,11 @@ int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, v
*/ struct acl *cond_find_require(struct acl_cond *cond, unsigned int require); +/* Walk through <cond_list> and return 0 if all tests fail or 1 if at last one test succeeds. + * This function checks the polarity required by IF/UNLESS. + */ +int check_cond_list(struct list *cond_list, struct proxy *px, struct session *l4, void *l7, int dir); + /* Return a pointer to the ACL <name> within the list starting at <head>, or * NULL if not found. */ diff --git a/include/types/proxy.h b/include/types/proxy.h index 5d0869c..b70a7e4 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h
@@ -112,6 +112,9 @@
#define PR_O2_SPLIC_AUT 0x00000004 /* automatically use linux kernel's splice() */ #define PR_O2_SPLIC_ANY (PR_O2_SPLIC_REQ|PR_O2_SPLIC_RTR|PR_O2_SPLIC_AUT) +#define PR_ORDER_DENY_ALLOW 0 /* last type of match wins: first evaluate deny_cond then allow_cond, allow by default */ +#define PR_ORDER_ALLOW_DENY 1 /* last type of match wins: first evaluate allow_cond then deny_cond, deny by default */ + /* This structure is used to apply fast weighted round robin on a server group */ struct fwrr_group { struct eb_root curr; /* tree for servers in "current" time range */
@@ -130,13 +133,15 @@ struct proxy {
int options; /* PR_O_REDISP, PR_O_TRANSP, ... */ int options2; /* PR_O2_* */ int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */ + int order; /* order = PR_ORDER_DENY_ALLOW or PR_ORDER_ALLOW_DENY */ struct sockaddr_in dispatch_addr; /* the default address to connect to */ union { struct proxy *be; /* default backend, or NULL if none set */ 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 list allow_cond; /* early allow blocking conditions (chained) */ + struct list deny_cond; /* early deny blocking conditions (chained) */ struct list redirect_rules; /* content redirecting rules (chained) */ struct list switching_rules; /* content switching rules (chained) */ struct { /* TCP request processing */ diff --git a/src/acl.c b/src/acl.c index ed41e91..8cab8df 100644 --- a/src/acl.c +++ b/src/acl.c
@@ -1119,6 +1119,25 @@ struct acl *cond_find_require(struct acl_cond *cond, unsigned int require)
return NULL; } +/* Walk through <cond_list> and return 0 if all tests fail or 1 if at last one test succeeds. + * This function checks the polarity required by IF/UNLESS. + */ +int check_cond_list(struct list *cond_list, struct proxy *px, struct session *l4, void *l7, int dir) { + + struct acl_cond *cond; + + list_for_each_entry(cond, cond_list, list) { + int ret = acl_exec_cond(cond, px, l4, l7, dir); + + if (cond->pol == ACL_COND_UNLESS) + ret = !ret; + + if (ret) + return 1; + } + + return 0; +} /************************************************************************/ /* All supported keywords must be declared here. */ diff --git a/src/cfgparse.c b/src/cfgparse.c index f98d07e..46f4ba7 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c
@@ -561,13 +561,15 @@ static void init_default_instance()
memset(&defproxy, 0, sizeof(defproxy)); defproxy.mode = PR_MODE_TCP; defproxy.state = PR_STNEW; + defproxy.order = PR_ORDER_DENY_ALLOW; defproxy.maxconn = cfg_maxpconn; defproxy.conn_retries = CONN_RETRIES; defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */ LIST_INIT(&defproxy.pendconns); LIST_INIT(&defproxy.acl); - LIST_INIT(&defproxy.block_cond); + LIST_INIT(&defproxy.allow_cond); + LIST_INIT(&defproxy.deny_cond); LIST_INIT(&defproxy.mon_fail_cond); LIST_INIT(&defproxy.switching_rules);
@@ -641,7 +643,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
proxy = curproxy; LIST_INIT(&curproxy->pendconns); LIST_INIT(&curproxy->acl); - LIST_INIT(&curproxy->block_cond); + LIST_INIT(&curproxy->allow_cond); + LIST_INIT(&curproxy->deny_cond); LIST_INIT(&curproxy->redirect_rules); LIST_INIT(&curproxy->mon_fail_cond); LIST_INIT(&curproxy->switching_rules);
@@ -668,6 +671,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
curproxy->state = defproxy.state; curproxy->options = defproxy.options; curproxy->options2 = defproxy.options2; + curproxy->order = defproxy.order; curproxy->lbprm.algo = defproxy.lbprm.algo; curproxy->except_net = defproxy.except_net; curproxy->except_mask = defproxy.except_mask;
@@ -1109,7 +1113,19 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
} curproxy->conn_retries = atol(args[1]); } - else if (!strcmp(args[0], "block")) { /* early blocking based on ACLs */ + else if (!strcmp(args[0], "order")) { + if (!strcasecmp(args[1], "allow,deny")) + curproxy->order = PR_ORDER_ALLOW_DENY; + else if (!strcasecmp(args[1], "deny,allow")) + curproxy->order = PR_ORDER_DENY_ALLOW; + else { + Alert("parsing [%s:%d]: unknow order '%s'.\n", + file, linenum, args[1]); + + return -1; + } + } + else if (!strcmp(args[0], "block") || !strcmp(args[0], "allow") || !strcmp(args[0], "deny")) { /* early blocking based on ACLs */ int pol = ACL_COND_NONE; struct acl_cond *cond;
@@ -1134,8 +1150,17 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
file, linenum); return -1; } + cond->line = linenum; - LIST_ADDQ(&curproxy->block_cond, &cond->list); + + if (!strcmp(args[0], "block")) + Alert("parsing [%s:%d]: '%s' is deprecated, please use 'deny' instead.\n", + file, linenum, args[0]); + + if (!strcmp(args[0], "allow")) + LIST_ADDQ(&curproxy->allow_cond, &cond->list); + else + LIST_ADDQ(&curproxy->deny_cond, &cond->list); } else if (!strcmp(args[0], "redirect")) { int pol = ACL_COND_NONE; diff --git a/src/haproxy.c b/src/haproxy.c index abf6eef..e7b8855 100644 --- a/src/haproxy.c +++ b/src/haproxy.c
@@ -687,7 +687,13 @@ void deinit(void)
for (i = 0; i < p->nb_rspadd; i++) free(p->rsp_add[i]); - list_for_each_entry_safe(cond, condb, &p->block_cond, list) { + list_for_each_entry_safe(cond, condb, &p->allow_cond, list) { + LIST_DEL(&cond->list); + prune_acl_cond(cond); + free(cond); + } + + list_for_each_entry_safe(cond, condb, &p->deny_cond, list) { LIST_DEL(&cond->list); prune_acl_cond(cond); free(cond); diff --git a/src/proto_http.c b/src/proto_http.c index ecbc887..34399aa 100644 --- a/src/proto_http.c +++ b/src/proto_http.c
@@ -1847,10 +1847,10 @@ int http_process_request(struct session *s, struct buffer *req)
*/ do { - struct acl_cond *cond; struct redirect_rule *rule; struct proxy *rule_set = s->be; cur_proxy = s->be; + int denyreq = 0; /* first check whether we have some ACLs set to redirect this request */ list_for_each_entry(rule, &cur_proxy->redirect_rules, list) {
@@ -1958,21 +1958,32 @@ int http_process_request(struct session *s, struct buffer *req)
} } - /* 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, s, txn, ACL_DIR_REQ); + /* check whether we should block this request */ + if (cur_proxy->order == PR_ORDER_ALLOW_DENY) { + denyreq = 1; - ret = acl_pass(ret); - if (cond->pol == ACL_COND_UNLESS) - ret = !ret; + if (check_cond_list(&cur_proxy->allow_cond, cur_proxy, s, txn, ACL_DIR_REQ)) + denyreq = 0; - if (ret) { - txn->status = 403; - /* let's log the request time */ - s->logs.tv_request = now; - stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_403)); - goto return_prx_cond; - } + if (check_cond_list(&cur_proxy->deny_cond, cur_proxy, s, txn, ACL_DIR_REQ)) + denyreq = 1; + + } else { + + if (check_cond_list(&cur_proxy->deny_cond, cur_proxy, s, txn, ACL_DIR_REQ)) + denyreq = 1; + + if (check_cond_list(&cur_proxy->allow_cond, cur_proxy, s, txn, ACL_DIR_REQ)) + denyreq = 0; + + } + + if (denyreq) { + txn->status = 403; + /* let's log the request time */ + s->logs.tv_request = now; + stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_403)); + goto return_prx_cond; } /* try headers filters */ -- 1.6.0.4
This archive was generated by hypermail 2.2.0 : 2009/01/27 18:00 CET