]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] config: replace 'tcp-request <action>' with "tcp-request connection"
authorWilly Tarreau <w@1wt.eu>
Fri, 6 Aug 2010 13:08:45 +0000 (15:08 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 10 Aug 2010 16:04:15 +0000 (18:04 +0200)
It began to be problematic to have "tcp-request" followed by an
immediate action, as sometimes it was a keyword indicating a hook
or setting ("content" or "inspect-delay") and sometimes it was an
action.

Now the prefix for connection-level tcp-requests is "tcp-request connection"
and the ones processing contents remain "tcp-request contents".

This has allowed a nice simplification of the config parser and to
clean up the doc a bit. Also now it's a bit more clear why tcp-request
connection are not allowed in backends.

doc/configuration.txt
src/proto_tcp.c

index e6e9727e8f21c2e497b7c8eea7f313f8d89398de..54c4b5efbfab848781c809343113e9f52af1a215 100644 (file)
@@ -962,11 +962,12 @@ stick match                               -          -         X         X
 stick on                                  -          -         X         X
 stick store-request                       -          -         X         X
 stick-table                               -          -         X         X
-tcp-request accept                        -          X         X         -
+tcp-request connection accept             -          X         X         -
+tcp-request connection reject             -          X         X         -
+tcp-request connection track-counters     -          X         X         -
 tcp-request content accept                -          X         X         -
 tcp-request content reject                -          X         X         -
 tcp-request inspect-delay                 -          X         X         -
-tcp-request reject                        -          X         X         -
 timeout check                             X          -         X         X
 timeout client                            X          X         X         -
 timeout clitimeout          (deprecated)  X          X         X         -
@@ -5251,7 +5252,7 @@ stick-table type {ip | integer | string [len <length>] } size <size>
              about time format and section 7 avoud ACLs.
 
 
-tcp-request accept [{if | unless} <condition>]
+tcp-request connection accept [{if | unless} <condition>]
   Accept an incoming connection if/unless a layer 4 condition is matched
   May be used in sections :   defaults | frontend | listen | backend
                                  no    |    yes   |   yes  |   no
@@ -5280,7 +5281,108 @@ tcp-request accept [{if | unless} <condition>]
 
   See section 7 about ACL usage.
 
-  See also : "tcp-request reject" and "tcp-request content"
+  See also : "tcp-request connection reject" and "tcp-request content"
+
+
+tcp-request connection reject [{if | unless} <condition>]
+  Reject an incoming connection if/unless a layer 4 condition is matched
+  May be used in sections :   defaults | frontend | listen | backend
+                                 no    |    yes   |   yes  |   no
+
+  Immediately after acceptance of a new incoming connection, it is possible to
+  evaluate some conditions to decide whether this connection must be accepted
+  or dropped. Those conditions cannot make use of any data contents because the
+  connection has not been read from yet, and the buffers are not yet allocated.
+  This can be used to selectively and very quickly accept or drop connections
+  from various sources with a very low overhead. If some contents need to be
+  inspected in order to take the decision, the "tcp-request content" statements
+  must be used instead.
+
+  This statement rejects the connection if the condition is true (when used
+  with "if") or false (when used with "unless"). It is important to understand
+  that "accept" and "reject" rules are evaluated in their exact declaration
+  order, so that it is possible to build complex rules from them. There is no
+  specific limit to the number of rules which may be inserted.
+
+  Note that the "if/unless" condition is optional. If no condition is set on
+  the action, it is simply performed unconditionally.
+
+  If no "tcp-request" rules are matched, the default action is to accept the
+  connection, which implies that the "tcp-request accept" statement will only
+  make sense when combined with another "tcp-request reject" statement.
+
+  Rejected connections do not even become a session, which is why they are
+  accounted separately for in the stats, as "denied connections". They are not
+  considered for the session rate-limit and are not logged either. The reason
+  is that these rules should only be used to filter extremely high connection
+  rates such as the ones encountered during a massive DDoS attack. Under these
+  conditions, the simple action of logging each event would make the system
+  collapse and would considerably lower the filtering capacity. If logging is
+  absolutely desired, then "tcp-request content" rules should be used instead.
+
+  See section 7 about ACL usage.
+
+  See also : "tcp-request connection accept" and "tcp-request content"
+
+
+tcp-request connection track-counters <key> [table <table>]
+                                      [{if | unless} <condition>]
+  Enable tracking of session counters if/unless a layer 4 condition is matched
+  May be used in sections :   defaults | frontend | listen | backend
+                                 no    |    yes   |   yes  |   no
+
+  Arguments :
+    <key>     is the criterion the tracking key will be derived from. At the
+              moment, only "src" is supported. With it, the key will be the
+              connection's source IPv4 address.
+
+    <table>   is an optional table to use instead of the one from the current
+              proxy. All the counters for the matches and updates for the key
+              will then be performed in that table.
+
+  Immediately after a new incoming connection has been accepted, it is possible
+  to enable tracking of some of this session's counters in a table. Doing so
+  serves two purposes :
+    - feed the entry with the session's counters that are relevant to the table
+      being pointed. These counters are then updated as often as possible, and
+      also systematically when the session ends.
+
+    - keep a pointer to the entry in the table in the session to avoid having
+      to perform key lookups when complex ACL rules make use of the entry,
+      especially when the key is expensive to compute (eg: header-based).
+
+  It is possible to evaluate some conditions to decide whether a track-counters
+  statement will apply or not. In this case, only the first matching rule will
+  apply and the other ones will be ignored. We could for instance imagine that
+  some hosts which are references in a white list make use of a different
+  counters table, or do not get accounted for. The tracking is enabled if the
+  condition is true (when used with "if") or false (when used with "unless").
+  There is no specific limit to the number of rules which may be declared.
+
+  It is important to understand that "accept", "reject" and "track-counters"
+  rules are evaluated in their exact declaration order, so that it is possible
+  to build complex rules from them. For instance, the following rule rejects
+  too fast connections without tracking them, to that they get accepted again
+  after some time despite activity, while the second one will still update the
+  counters when rejecting a connection.
+
+  Example:
+        # reject too fast connection without counting them
+        tcp-request connection reject if { src_conn_rate gt 10 }
+        tcp-request connection track-counters src
+
+        # reject too fast connection and count them
+        tcp-request connection track-counters src
+        tcp-request connection reject if { src_conn_rate gt 10 }
+
+
+  Note that the "if/unless" condition is optional. If no condition is set on
+  the action, it is simply performed unconditionally.
+
+  See section 7 about ACL usage.
+
+  See also : "tcp-request connection accept", "tcp-request connection reject",
+             "tcp-request content", and "stick-table".
 
 
 tcp-request content accept [{if | unless} <condition>]
@@ -5337,12 +5439,12 @@ tcp-request content reject [{if | unless} <condition>]
         # reject SMTP connection if client speaks first
         tcp-request inspect-delay 30s
         acl content_present req_len gt 0
-        tcp-request reject if content_present
+        tcp-request content reject if content_present
 
         # Forward HTTPS connection only if client speaks
         tcp-request inspect-delay 30s
         acl content_present req_len gt 0
-        tcp-request accept if content_present
+        tcp-request content accept if content_present
         tcp-request reject
 
   See section 7 about ACL usage.
@@ -5395,106 +5497,6 @@ tcp-request inspect-delay <timeout>
              "timeout client".
 
 
-tcp-request reject [{if | unless} <condition>]
-  Reject an incoming connection if/unless a layer 4 condition is matched
-  May be used in sections :   defaults | frontend | listen | backend
-                                 no    |    yes   |   yes  |   no
-
-  Immediately after acceptance of a new incoming connection, it is possible to
-  evaluate some conditions to decide whether this connection must be accepted
-  or dropped. Those conditions cannot make use of any data contents because the
-  connection has not been read from yet, and the buffers are not yet allocated.
-  This can be used to selectively and very quickly accept or drop connections
-  from various sources with a very low overhead. If some contents need to be
-  inspected in order to take the decision, the "tcp-request content" statements
-  must be used instead.
-
-  This statement rejects the connection if the condition is true (when used
-  with "if") or false (when used with "unless"). It is important to understand
-  that "accept" and "reject" rules are evaluated in their exact declaration
-  order, so that it is possible to build complex rules from them. There is no
-  specific limit to the number of rules which may be inserted.
-
-  Note that the "if/unless" condition is optional. If no condition is set on
-  the action, it is simply performed unconditionally.
-
-  If no "tcp-request" rules are matched, the default action is to accept the
-  connection, which implies that the "tcp-request accept" statement will only
-  make sense when combined with another "tcp-request reject" statement.
-
-  Rejected connections do not even become a session, which is why they are
-  accounted separately for in the stats, as "denied connections". They are not
-  considered for the session rate-limit and are not logged either. The reason
-  is that these rules should only be used to filter extremely high connection
-  rates such as the ones encountered during a massive DDoS attack. Under these
-  conditions, the simple action of logging each event would make the system
-  collapse and would considerably lower the filtering capacity. If logging is
-  absolutely desired, then "tcp-request content" rules should be used instead.
-
-  See section 7 about ACL usage.
-
-  See also : "tcp-request accept" and "tcp-request content"
-
-
-tcp-request track-counters <key> [table <table>] [{if | unless} <condition>]
-  Enable tracking of session counters if/unless a layer 4 condition is matched
-  May be used in sections :   defaults | frontend | listen | backend
-                                 no    |    yes   |   yes  |   no
-
-  Arguments :
-    <key>     is the criterion the tracking key will be derived from. At the
-              moment, only "src" is supported. With it, the key will be the
-              connection's source IPv4 address.
-
-    <table>   is an optional table to use instead of the one from the current
-              proxy. All the counters for the matches and updates for the key
-              will then be performed in that table.
-
-  Immediately after a new incoming connection has been accepted, it is possible
-  to enable tracking of some of this session's counters in a table. Doing so
-  serves two purposes :
-    - feed the entry with the session's counters that are relevant to the table
-      being pointed. These counters are then updated as often as possible, and
-      also systematically when the session ends.
-
-    - keep a pointer to the entry in the table in the session to avoid having
-      to perform key lookups when complex ACL rules make use of the entry,
-      especially when the key is expensive to compute (eg: header-based).
-
-  It is possible to evaluate some conditions to decide whether a track-counters
-  statement will apply or not. In this case, only the first matching rule will
-  apply and the other ones will be ignored. We could for instance imagine that
-  some hosts which are references in a white list make use of a different
-  counters table, or do not get accounted for. The tracking is enabled if the
-  condition is true (when used with "if") or false (when used with "unless").
-  There is no specific limit to the number of rules which may be declared.
-
-  It is important to understand that "accept", "reject" and "track-counters"
-  rules are evaluated in their exact declaration order, so that it is possible
-  to build complex rules from them. For instance, the following rule rejects
-  too fast connections without tracking them, to that they get accepted again
-  after some time despite activity, while the second one will still update the
-  counters when rejecting a connection.
-
-  Example:
-        # reject too fast connection without counting them
-        tcp-request reject if { src_conn_rate gt 10 }
-        tcp-request track-counters src
-
-        # reject too fast connection and count them
-        tcp-request track-counters src
-        tcp-request reject if { src_conn_rate gt 10 }
-
-
-  Note that the "if/unless" condition is optional. If no condition is set on
-  the action, it is simply performed unconditionally.
-
-  See section 7 about ACL usage.
-
-  See also : "tcp-request accept", "tcp-request reject", "tcp-request content",
-             and "stick-table".
-
-
 timeout check <timeout>
   Set additional check timeout, but only after a connection has been already
   established.
index e87860b5e444f066c9f86340a4cef67fb374da96..66b8a131e6f38afad14ee1e59eb7e6915d37e1b7 100644 (file)
@@ -799,6 +799,74 @@ int tcp_exec_req_rules(struct session *s)
        return result;
 }
 
+/* Parse a tcp-request rule. Return a negative value in case of failure */
+static int tcp_parse_request_rule(char **args, int arg, int section_type,
+                                 struct proxy *curpx, struct proxy *defpx,
+                                 struct tcp_rule *rule, char *err, int errlen)
+{
+       if (curpx == defpx) {
+               snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
+                        args[0], args[1]);
+               return -1;
+       }
+
+       if (!strcmp(args[arg], "accept")) {
+               arg++;
+               rule->action = TCP_ACT_ACCEPT;
+       }
+       else if (!strcmp(args[arg], "reject")) {
+               arg++;
+               rule->action = TCP_ACT_REJECT;
+       }
+       else if (strcmp(args[arg], "track-fe-counters") == 0) {
+               int ret;
+
+               arg++;
+               ret = parse_track_counters(args, &arg, section_type, curpx,
+                                          &rule->act_prm.trk_ctr, defpx, err, errlen);
+
+               if (ret < 0) /* nb: warnings are not handled yet */
+                       return -1;
+
+               rule->action = TCP_ACT_TRK_FE_CTR;
+       }
+       else if (strcmp(args[arg], "track-be-counters") == 0) {
+               int ret;
+
+               arg++;
+               ret = parse_track_counters(args, &arg, section_type, curpx,
+                                          &rule->act_prm.trk_ctr, defpx, err, errlen);
+
+               if (ret < 0) /* nb: warnings are not handled yet */
+                       return -1;
+
+               rule->action = TCP_ACT_TRK_BE_CTR;
+       }
+       else {
+               snprintf(err, errlen,
+                        "'%s %s' expects 'accept', 'reject', 'track-fe-counters' "
+                        "or 'track-be-counters' in %s '%s' (was '%s')",
+                        args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]);
+               return -1;
+       }
+
+       if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
+               if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
+                       snprintf(err, errlen,
+                                "error detected in %s '%s' while parsing '%s' condition",
+                                proxy_type_str(curpx), curpx->id, args[arg]);
+                       return -1;
+               }
+       }
+       else if (*args[arg]) {
+               snprintf(err, errlen,
+                        "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
+                        args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
+               return -1;
+       }
+       return 0;
+}
+
 /* This function should be called to parse a line starting with the "tcp-request"
  * keyword.
  */
@@ -809,7 +877,6 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
        unsigned int val;
        int retlen;
        int warn = 0;
-       int pol = ACL_COND_NONE;
        int arg;
        struct tcp_rule *rule;
 
@@ -848,70 +915,10 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
        rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
        arg = 1;
 
-       if (!strcmp(args[1], "content")) {
+       if (strcmp(args[1], "content") == 0) {
                arg++;
-               if (curpx == defpx) {
-                       snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
-                                args[0], args[1]);
-                       goto error;
-               }
-
-               if (!strcmp(args[2], "accept")) {
-                       arg++;
-                       rule->action = TCP_ACT_ACCEPT;
-               }
-               else if (!strcmp(args[2], "reject")) {
-                       arg++;
-                       rule->action = TCP_ACT_REJECT;
-               }
-               else if (strcmp(args[2], "track-fe-counters") == 0) {
-                       int ret;
-
-                       arg++;
-                       ret = parse_track_counters(args, &arg, section_type, curpx,
-                                                  &rule->act_prm.trk_ctr, defpx, err, errlen);
-
-                       if (ret < 0) /* nb: warnings are not handled yet */
-                               goto error;
-
-                       rule->action = TCP_ACT_TRK_FE_CTR;
-               }
-               else if (strcmp(args[2], "track-be-counters") == 0) {
-                       int ret;
-
-                       arg++;
-                       ret = parse_track_counters(args, &arg, section_type, curpx,
-                                                  &rule->act_prm.trk_ctr, defpx, err, errlen);
-
-                       if (ret < 0) /* nb: warnings are not handled yet */
-                               goto error;
-
-                       rule->action = TCP_ACT_TRK_BE_CTR;
-               }
-               else {
-                       retlen = snprintf(err, errlen,
-                                         "'%s %s' expects 'accept', 'reject', 'track-fe-counters' or 'track-be-counters' in %s '%s' (was '%s')",
-                                         args[0], args[1], proxy_type_str(curpx), curpx->id, args[2]);
+               if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0)
                        goto error;
-               }
-
-               pol = ACL_COND_NONE;
-               rule->cond = NULL;
-
-               if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
-                       if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
-                               retlen = snprintf(err, errlen,
-                                                 "error detected in %s '%s' while parsing '%s' condition",
-                                                 proxy_type_str(curpx), curpx->id, args[arg]);
-                               goto error;
-                       }
-               }
-               else if (*args[arg]) {
-                       retlen = snprintf(err, errlen,
-                                         "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
-                                         args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
-                       goto error;
-               }
 
                if (rule->cond && (rule->cond->requires & ACL_USE_RTR_ANY)) {
                        struct acl *acl;
@@ -925,96 +932,47 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
                                          name);
                        warn++;
                }
-               LIST_INIT(&rule->list);
-               LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
-               return warn;
-       }
-
-       /* OK so we're in front of plain L4 rules */
-
-       if (strcmp(args[1], "accept") == 0) {
-               arg++;
-               rule->action = TCP_ACT_ACCEPT;
        }
-       else if (strcmp(args[1], "reject") == 0) {
+       else if (strcmp(args[1], "connection") == 0) {
                arg++;
-               rule->action = TCP_ACT_REJECT;
-       }
-       else if (strcmp(args[1], "track-fe-counters") == 0) {
-               int ret;
 
-               arg++;
-               ret = parse_track_counters(args, &arg, section_type, curpx,
-                                          &rule->act_prm.trk_ctr, defpx, err, errlen);
+               if (!(curpx->cap & PR_CAP_FE)) {
+                       snprintf(err, errlen, "%s %s is not allowed because %s %s is not a frontend",
+                                args[0], args[1], proxy_type_str(curpx), curpx->id);
+                       return -1;
+               }
 
-               if (ret < 0) /* nb: warnings are not handled yet */
+               if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0)
                        goto error;
 
-               rule->action = TCP_ACT_TRK_FE_CTR;
-       }
-       else if (strcmp(args[1], "track-be-counters") == 0) {
-               int ret;
-
-               arg++;
-               ret = parse_track_counters(args, &arg, section_type, curpx,
-                                          &rule->act_prm.trk_ctr, defpx, err, errlen);
+               if (rule->cond && (rule->cond->requires & (ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY))) {
+                       struct acl *acl;
+                       const char *name;
 
-               if (ret < 0) /* nb: warnings are not handled yet */
-                       goto error;
+                       acl = cond_find_require(rule->cond, ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY);
+                       name = acl ? acl->name : "(unknown)";
 
-               rule->action = TCP_ACT_TRK_BE_CTR;
+                       if (acl->requires & (ACL_USE_L6_ANY|ACL_USE_L7_ANY)) {
+                               retlen = snprintf(err, errlen,
+                                                 "'%s %s' may not reference acl '%s' which makes use of "
+                                                 "payload in %s '%s'. Please use '%s content' for this.",
+                                                 args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]);
+                               goto error;
+                       }
+                       if (acl->requires & ACL_USE_RTR_ANY)
+                               retlen = snprintf(err, errlen,
+                                                 "acl '%s' involves some response-only criteria which will be ignored.",
+                                                 name);
+                       warn++;
+               }
        }
        else {
                retlen = snprintf(err, errlen,
-                                 "'%s' expects 'inspect-delay', 'content', 'accept', 'reject', 'track-fe-counters' or 'track-be-counters' in %s '%s' (was '%s')",
+                                 "'%s' expects 'inspect-delay', 'connection', or 'content' in %s '%s' (was '%s')",
                                  args[0], proxy_type_str(curpx), curpx->id, args[1]);
                goto error;
        }
 
-       if (curpx == defpx) {
-               snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
-                        args[0], args[1]);
-               goto error;
-       }
-
-       pol = ACL_COND_NONE;
-
-       if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
-               if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
-                       retlen = snprintf(err, errlen,
-                                         "error detected in %s '%s' while parsing '%s' condition",
-                                         proxy_type_str(curpx), curpx->id, args[arg]);
-                       goto error;
-               }
-       }
-       else if (*args[arg]) {
-               retlen = snprintf(err, errlen,
-                                 "'%s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
-                                 args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]);
-               goto error;
-       }
-
-       if (rule->cond && (rule->cond->requires & (ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY))) {
-               struct acl *acl;
-               const char *name;
-
-               acl = cond_find_require(rule->cond, ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY);
-               name = acl ? acl->name : "(unknown)";
-
-               if (acl->requires & (ACL_USE_L6_ANY|ACL_USE_L7_ANY)) {
-                       retlen = snprintf(err, errlen,
-                                         "'%s %s' may not reference acl '%s' which makes use of payload in %s '%s'. Please use '%s content' for this.",
-                                         args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]);
-                       goto error;
-               }
-               if (acl->requires & ACL_USE_RTR_ANY)
-                       retlen = snprintf(err, errlen,
-                                         "acl '%s' involves some response-only criteria which will be ignored.",
-                                         name);
-
-               warn++;
-       }
-
        LIST_INIT(&rule->list);
        LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list);
        return warn;