MEDIUM: rules/acl: Parse TCP/HTTP rules and acls defined in defaults sections

TCP and HTTP rules can now be defined in defaults sections, but only those
with a name. Because these rules may use conditions based on ACLs, ACLs can
also be defined in defaults sections.

However there are some limitations:

  * A defaults section defining TCP/HTTP rules cannot be used by a defaults
    section
  * A defaults section defining TCP/HTTP rules cannot be used bu a listen
    section
  * A defaults sections defining TCP/HTTP rules cannot be used by frontends
    and backends at the same time
  * A defaults sections defining 'tcp-request connection' or 'tcp-request
    session' rules cannot be used by backends
  * A defaults sections defining 'tcp-response content' rules cannot be used
    by frontends

The TCP request/response inspect-delay of a proxy is now inherited from the
defaults section it uses. For now, these rules are only parsed. No evaluation is
performed.
This commit is contained in:
Christopher Faulet 2021-10-13 15:40:15 +02:00
parent 6ff7de5d64
commit ee08d6cc74
4 changed files with 99 additions and 23 deletions

View File

@ -333,6 +333,70 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out;
}
if (curr_defproxy && (!LIST_ISEMPTY(&curr_defproxy->http_req_rules) ||
!LIST_ISEMPTY(&curr_defproxy->http_res_rules) ||
!LIST_ISEMPTY(&curr_defproxy->http_after_res_rules) ||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.l4_rules) ||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.l5_rules) ||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.inspect_rules) ||
!LIST_ISEMPTY(&curr_defproxy->tcp_rep.inspect_rules))) {
/* If the current default proxy defines TCP/HTTP rules, the
* current proxy will keep a reference on it. But some sanity
* checks are performed first:
*
* - It cannot be used to init a defaults section
* - It cannot be used to init a listen section
* - It cannot be used to init backend and frontend sections at
* same time. It can be used to init several sections of the
* same type only.
* - It cannot define L4/L5 TCP rules if it is used to init
* backend sections.
* - It cannot define 'tcp-response content' rules if it
* is used to init frontend sections.
*
* If no error is found, refcount of the default proxy is incremented.
*/
/* Note: Add tcpcheck_rules too if unresolve args become allowed in defaults section */
if (rc & PR_CAP_DEF) {
ha_alert("parsing [%s:%d]: a defaults section cannot inherit from a defaults section defining TCP/HTTP rules (defaults section at %s:%d).\n",
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
err_code |= ERR_ALERT | ERR_ABORT;
}
else if ((rc & PR_CAP_LISTEN) == PR_CAP_LISTEN) {
ha_alert("parsing [%s:%d]: a listen section cannot inherit from a defaults section defining TCP/HTTP rules.\n",
file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
}
else {
char defcap = (curr_defproxy->cap & PR_CAP_LISTEN);
if ((defcap == PR_CAP_BE || defcap == PR_CAP_FE) && (rc & PR_CAP_LISTEN) != defcap) {
ha_alert("parsing [%s:%d]: frontends and backends cannot inherit from the same defaults section"
" if it defines TCP/HTTP rules (defaults section at %s:%d).\n",
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
err_code |= ERR_ALERT | ERR_ABORT;
}
else if (!(rc & PR_CAP_FE) && (!LIST_ISEMPTY(&curr_defproxy->tcp_req.l4_rules) ||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.l5_rules))) {
ha_alert("parsing [%s:%d]: a backend section cannot inherit from a defaults section defining"
" 'tcp-request connection' or 'tcp-request session' rules (defaults section at %s:%d).\n",
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
err_code |= ERR_ALERT | ERR_ABORT;
}
else if (!(rc & PR_CAP_BE) && !LIST_ISEMPTY(&curr_defproxy->tcp_rep.inspect_rules)) {
ha_alert("parsing [%s:%d]: a frontend section cannot inherit from a defaults section defining"
" 'tcp-response content' rules (defaults section at %s:%d).\n",
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
err_code |= ERR_ALERT | ERR_ABORT;
}
else {
curr_defproxy->cap = (curr_defproxy->cap & ~PR_CAP_LISTEN) | (rc & PR_CAP_LISTEN);
proxy_ref_defaults(curproxy, curr_defproxy);
}
}
}
if (curr_defproxy && (curr_defproxy->tcpcheck_rules.flags & TCPCHK_RULES_PROTO_CHK) &&
(curproxy->cap & PR_CAP_LISTEN) == PR_CAP_BE) {
/* If the current default proxy defines tcpcheck rules, the
@ -641,8 +705,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
err_code |= ERR_WARN;
}
else if (strcmp(args[0], "acl") == 0) { /* add an ACL */
if (curproxy->cap & PR_CAP_DEF) {
ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
if ((curproxy->cap & PR_CAP_DEF) && strlen(curproxy->id) == 0) {
ha_alert("parsing [%s:%d] : '%s' not allowed in anonymous 'defaults' section.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@ -1212,8 +1276,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
else if (strcmp(args[0], "http-request") == 0) { /* request access control: allow/deny/auth */
struct act_rule *rule;
if (curproxy->cap & PR_CAP_DEF) {
ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
if ((curproxy->cap & PR_CAP_DEF) && strlen(curproxy->id) == 0) {
ha_alert("parsing [%s:%d] : '%s' not allowed in anonymous 'defaults' section.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@ -1243,8 +1307,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
else if (strcmp(args[0], "http-response") == 0) { /* response access control */
struct act_rule *rule;
if (curproxy->cap & PR_CAP_DEF) {
ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
if ((curproxy->cap & PR_CAP_DEF) && strlen(curproxy->id) == 0) {
ha_alert("parsing [%s:%d] : '%s' not allowed in anonymous 'defaults' section.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@ -1273,8 +1337,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
else if (strcmp(args[0], "http-after-response") == 0) {
struct act_rule *rule;
if (curproxy->cap & PR_CAP_DEF) {
ha_alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
if ((curproxy->cap & PR_CAP_DEF) && strlen(curproxy->id) == 0) {
ha_alert("parsing [%s:%d] : '%s' not allowed in anonymous 'defaults' section.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}

View File

@ -2520,6 +2520,15 @@ int check_config_validity()
*/
if (curproxy->defpx) {
if (!(curproxy->defpx->flags & PR_FL_READY)) {
/* check validity for 'tcp-request' layer 4/5/6/7 rules */
cfgerr += check_action_rules(&curproxy->defpx->tcp_req.l4_rules, curproxy->defpx, &err_code);
cfgerr += check_action_rules(&curproxy->defpx->tcp_req.l5_rules, curproxy->defpx, &err_code);
cfgerr += check_action_rules(&curproxy->defpx->tcp_req.inspect_rules, curproxy->defpx, &err_code);
cfgerr += check_action_rules(&curproxy->defpx->tcp_rep.inspect_rules, curproxy->defpx, &err_code);
cfgerr += check_action_rules(&curproxy->defpx->http_req_rules, curproxy->defpx, &err_code);
cfgerr += check_action_rules(&curproxy->defpx->http_res_rules, curproxy->defpx, &err_code);
cfgerr += check_action_rules(&curproxy->defpx->http_after_res_rules, curproxy->defpx, &err_code);
err = NULL;
i = smp_resolve_args(curproxy->defpx, &err);
cfgerr += i;
@ -3612,8 +3621,8 @@ out_uri_auth_compat:
if (!curproxy->accept)
curproxy->accept = frontend_accept;
if (curproxy->tcp_req.inspect_delay ||
!LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules))
if (!LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules) ||
(curproxy->defpx && !LIST_ISEMPTY(&curproxy->defpx->tcp_req.inspect_rules)))
curproxy->fe_req_ana |= AN_REQ_INSPECT_FE;
if (curproxy->mode == PR_MODE_HTTP) {
@ -3637,11 +3646,12 @@ out_uri_auth_compat:
}
if (curproxy->cap & PR_CAP_BE) {
if (curproxy->tcp_req.inspect_delay ||
!LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules))
if (!LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules) ||
(curproxy->defpx && !LIST_ISEMPTY(&curproxy->defpx->tcp_req.inspect_rules)))
curproxy->be_req_ana |= AN_REQ_INSPECT_BE;
if (!LIST_ISEMPTY(&curproxy->tcp_rep.inspect_rules))
if (!LIST_ISEMPTY(&curproxy->tcp_rep.inspect_rules) ||
(curproxy->defpx && !LIST_ISEMPTY(&curproxy->defpx->tcp_rep.inspect_rules)))
curproxy->be_rsp_ana |= AN_RES_INSPECT;
if (curproxy->mode == PR_MODE_HTTP) {

View File

@ -1576,6 +1576,8 @@ static int proxy_defproxy_cpy(struct proxy *curproxy, const struct proxy *defpro
curproxy->except_xff_net = defproxy->except_xff_net;
curproxy->except_xot_net = defproxy->except_xot_net;
curproxy->retry_type = defproxy->retry_type;
curproxy->tcp_req.inspect_delay = defproxy->tcp_req.inspect_delay;
curproxy->tcp_rep.inspect_delay = defproxy->tcp_rep.inspect_delay;
if (defproxy->fwdfor_hdr_len) {
curproxy->fwdfor_hdr_len = defproxy->fwdfor_hdr_len;

View File

@ -574,8 +574,8 @@ static int tcp_parse_response_rule(char **args, int arg, int section_type,
unsigned int where,
const char *file, int line)
{
if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
memprintf(err, "%s %s is only allowed in 'backend' sections",
if ((curpx == defpx && strlen(defpx->id) == 0) || !(curpx->cap & PR_CAP_BE)) {
memprintf(err, "%s %s is only allowed in 'backend' sections or 'defaults' section with a name",
args[0], args[1]);
return -1;
}
@ -742,9 +742,9 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type,
struct act_rule *rule, char **err,
unsigned int where, const char *file, int line)
{
if (curpx == defpx) {
memprintf(err, "%s %s is not allowed in 'defaults' sections",
args[0], args[1]);
if (curpx == defpx && strlen(defpx->id) == 0) {
memprintf(err, "%s %s is not allowed in anonymous 'defaults' sections",
args[0], args[1]);
return -1;
}
@ -1031,8 +1031,8 @@ static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx,
}
if (strcmp(args[1], "inspect-delay") == 0) {
if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
memprintf(err, "%s %s is only allowed in 'backend' sections",
if ((curpx == defpx && strlen(defpx->id) == 0) || !(curpx->cap & PR_CAP_BE)) {
memprintf(err, "%s %s is only allowed in 'backend' sections or 'defaults' section with a name",
args[0], args[1]);
return -1;
}
@ -1148,9 +1148,9 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
}
if (strcmp(args[1], "inspect-delay") == 0) {
if (curpx == defpx) {
memprintf(err, "%s %s is not allowed in 'defaults' sections",
args[0], args[1]);
if (curpx == defpx && strlen(defpx->id) == 0) {
memprintf(err, "%s %s is not allowed in anonymous 'defaults' sections",
args[0], args[1]);
return -1;
}