MEDIUM: tcp-rules: Eval TCP rules defined in defaults sections
TCP rules from defaults section are now evaluated. These rules are evaluated
before those of the proxy. For L7 TCP rules, the same default ruleset cannot
be attached to the frontend and the backend. However, at this stage, we take
care to not execute twice the same ruleset. So, in theory, a frontend and a
backend could use the same defaults section. In this case, the default
ruleset is executed before all others and only once.
diff --git a/src/tcp_rules.c b/src/tcp_rules.c
index 5d97b25..886dd9e 100644
--- a/src/tcp_rules.c
+++ b/src/tcp_rules.c
@@ -94,6 +94,7 @@
*/
int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit)
{
+ struct list *def_rules, *rules;
struct session *sess = s->sess;
struct act_rule *rule;
int partial;
@@ -101,6 +102,9 @@
DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
+ def_rules = ((s->be->defpx && (an_bit == AN_REQ_INSPECT_FE || s->be->defpx != sess->fe->defpx)) ? &s->be->defpx->tcp_req.inspect_rules : NULL);
+ rules = &s->be->tcp_req.inspect_rules;
+
/* We don't know whether we have enough data, so must proceed
* this way :
* - iterate through all rules in their declaration order
@@ -126,12 +130,13 @@
if (s->current_rule) {
rule = s->current_rule;
s->current_rule = NULL;
- if (s->current_rule_list == &s->be->tcp_req.inspect_rules)
+ if ((def_rules && s->current_rule_list == def_rules) || s->current_rule_list == rules)
goto resume_execution;
}
- s->current_rule_list = &s->be->tcp_req.inspect_rules;
+ s->current_rule_list = ((!def_rules || s->current_rule_list == def_rules) ? rules : def_rules);
- list_for_each_entry(rule, &s->be->tcp_req.inspect_rules, list) {
+ restart:
+ list_for_each_entry(rule, s->current_rule_list, list) {
enum acl_test_res ret = ACL_TEST_PASS;
if (rule->cond) {
@@ -190,11 +195,17 @@
}
}
+ if (def_rules && s->current_rule_list == def_rules) {
+ s->current_rule_list = rules;
+ goto restart;
+ }
+
end:
/* if we get there, it means we have no rule which matches, or
* we have an explicit accept, so we apply the default accept.
*/
req->analysers &= ~an_bit;
+ s->current_rule = s->current_rule_list = NULL;
req->analyse_exp = s->rules_exp = TICK_ETERNITY;
DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
return 1;
@@ -234,6 +245,8 @@
abort:
req->analysers &= AN_REQ_FLT_END;
+ s->current_rule = s->current_rule_list = NULL;
+ req->analyse_exp = s->rules_exp = TICK_ETERNITY;
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
@@ -251,6 +264,7 @@
*/
int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit)
{
+ struct list *def_rules, *rules;
struct session *sess = s->sess;
struct act_rule *rule;
int partial;
@@ -258,6 +272,9 @@
DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
+ def_rules = (s->be->defpx ? &s->be->defpx->tcp_rep.inspect_rules : NULL);
+ rules = &s->be->tcp_rep.inspect_rules;
+
/* We don't know whether we have enough data, so must proceed
* this way :
* - iterate through all rules in their declaration order
@@ -282,13 +299,13 @@
if (s->current_rule) {
rule = s->current_rule;
s->current_rule = NULL;
- if (s->current_rule_list == &s->be->tcp_rep.inspect_rules)
+ if ((def_rules && s->current_rule_list == def_rules) || s->current_rule_list == rules)
goto resume_execution;
}
- s->current_rule_list = &s->be->tcp_rep.inspect_rules;
- s->rules_exp = TICK_ETERNITY;
+ s->current_rule_list = ((!def_rules || s->current_rule_list == def_rules) ? rules : def_rules);
- list_for_each_entry(rule, &s->be->tcp_rep.inspect_rules, list) {
+ restart:
+ list_for_each_entry(rule, s->current_rule_list, list) {
enum acl_test_res ret = ACL_TEST_PASS;
if (rule->cond) {
@@ -354,11 +371,17 @@
}
}
+ if (def_rules && s->current_rule_list == def_rules) {
+ s->current_rule_list = rules;
+ goto restart;
+ }
+
end:
/* if we get there, it means we have no rule which matches, or
* we have an explicit accept, so we apply the default accept.
*/
rep->analysers &= ~an_bit;
+ s->current_rule = s->current_rule_list = NULL;
rep->analyse_exp = s->rules_exp = TICK_ETERNITY;
DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
return 1;
@@ -403,6 +426,8 @@
abort:
rep->analysers &= AN_RES_FLT_END;
+ s->current_rule = s->current_rule_list = NULL;
+ rep->analyse_exp = s->rules_exp = TICK_ETERNITY;
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
@@ -420,6 +445,7 @@
*/
int tcp_exec_l4_rules(struct session *sess)
{
+ struct proxy *px = sess->fe;
struct act_rule *rule;
struct connection *conn = objt_conn(sess->origin);
int result = 1;
@@ -428,7 +454,11 @@
if (!conn)
return result;
+ if (sess->fe->defpx)
+ px = sess->fe->defpx;
+
- list_for_each_entry(rule, &sess->fe->tcp_req.l4_rules, list) {
+ restart:
+ list_for_each_entry(rule, &px->tcp_req.l4_rules, list) {
ret = ACL_TEST_PASS;
if (rule->cond) {
@@ -496,6 +526,11 @@
}
}
}
+
+ if (px != sess->fe) {
+ px = sess->fe;
+ goto restart;
+ }
end:
return result;
}
@@ -509,11 +544,16 @@
*/
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;
- list_for_each_entry(rule, &sess->fe->tcp_req.l5_rules, list) {
+ if (sess->fe->defpx)
+ px = sess->fe->defpx;
+
+ restart:
+ list_for_each_entry(rule, &px->tcp_req.l5_rules, list) {
ret = ACL_TEST_PASS;
if (rule->cond) {
@@ -563,6 +603,11 @@
}
}
}
+
+ if (px != sess->fe) {
+ px = sess->fe;
+ goto restart;
+ }
end:
return result;
}