Willy Tarreau | 6cee7dd | 2011-12-16 21:51:00 +0100 | [diff] [blame] | 1 | 2011/12/16 - How ACLs work internally in haproxy - w@1wt.eu |
| 2 | |
| 3 | An ACL is declared by the keyword "acl" followed by a name, followed by a |
| 4 | matching method, followed by one or multiple pattern values : |
| 5 | |
| 6 | acl internal src 127.0.0.0/8 10.0.0.0/8 192.168.0.0/16 |
| 7 | |
| 8 | In the statement above, "internal" is the ACL's name (acl->name), "src" is the |
| 9 | ACL keyword defining the matching method (acl_expr->kw) and the IP addresses |
| 10 | are patterns of type acl_pattern to match against the source address. |
| 11 | |
| 12 | The acl_pattern struct may define one single pattern, a range of values or a |
| 13 | tree of values to match against. The type of the patterns is implied by the |
| 14 | ACL keyword. For instance, the "src" keyword implies IPv4 patterns. |
| 15 | |
| 16 | The line above constitutes an ACL expression (acl_expr). ACL expressions are |
| 17 | formed of a keyword, an optional argument for the keyword, and a list of |
| 18 | patterns (in fact, both a list and a root tree). |
| 19 | |
| 20 | Dynamic values are extracted according to a fetch function defined by the ACL |
| 21 | keyword. This fetch function fills or updates a struct acl_test with all the |
| 22 | extracted information so that a match function can compare it against all the |
| 23 | patterns. The fetch function is called iteratively by the ACL engine until it |
| 24 | reports no more value. This makes sense for instance when checking IP addresses |
| 25 | found in HTTP headers, which can appear multiple times. The acl_test is kept |
| 26 | intact between calls and even holds a context so that the fetch function knows |
| 27 | where to start from for subsequent calls. The match function may also use the |
| 28 | context eventhough it was not designed for that purpose. |
| 29 | |
| 30 | An ACL is defined only by its name and can be a series of ACL expressions. The |
| 31 | ACL is deemed true when any of its expressions is true. They are evaluated in |
| 32 | the declared order and can involve multiple matching methods. |
| 33 | |
| 34 | So in summary : |
| 35 | |
| 36 | - an ACL is a series of tests to perform on a stream, any of which is enough |
| 37 | to validate the result. |
| 38 | |
| 39 | - each test is defined by an expression associating a keyword and a series of |
| 40 | patterns. |
| 41 | |
| 42 | - a keyword implies several things at once : |
| 43 | - the type of the patterns and how to parse them |
| 44 | - the method to fetch the required information from the stream |
| 45 | - the method to match the fetched information against the patterns |
| 46 | |
| 47 | - a fetch function fills an acl_test struct which is passed to the match |
| 48 | function defined by the keyword |
| 49 | |
| 50 | - the match function tries to match the value in the acl_test against the |
| 51 | pattern list declared in the expression which involved its acl_keyword. |
| 52 | |
| 53 | |
| 54 | ACLs are used by conditional processing rules. A rule generally uses an "if" or |
| 55 | "unless" keyword followed by an ACL condition (acl_cond). This condition is a |
| 56 | series of term suites which are ORed together. Each term suite is a series of |
| 57 | terms which are ANDed together. Terms may be negated before being evaluated in |
| 58 | a suite. A term simply is a pointer to an ACL. |
| 59 | |
| 60 | We could then represent a rule by the following BNF : |
| 61 | |
| 62 | rule = if-cond |
| 63 | | unless-cond |
| 64 | |
| 65 | if-cond (struct acl_cond with ->pol = ACL_COND_IF) |
| 66 | = "if" condition |
| 67 | |
| 68 | unless-cond (struct acl_cond with ->pol = ACL_COND_UNLESS) |
| 69 | = "unless" condition |
| 70 | |
| 71 | condition |
| 72 | = term-suite |
| 73 | | term-suite "||" term-suite |
| 74 | | term-suite "or" term-suite |
| 75 | |
| 76 | term-suite (struct acl_term_suite) |
| 77 | = term |
| 78 | | term term |
| 79 | |
| 80 | term = acl |
| 81 | | "!" acl |
| 82 | |