2011-12-16 20:51:00 +00:00
|
|
|
2011/12/16 - How ACLs work internally in haproxy - w@1wt.eu
|
|
|
|
|
|
|
|
An ACL is declared by the keyword "acl" followed by a name, followed by a
|
|
|
|
matching method, followed by one or multiple pattern values :
|
|
|
|
|
|
|
|
acl internal src 127.0.0.0/8 10.0.0.0/8 192.168.0.0/16
|
|
|
|
|
|
|
|
In the statement above, "internal" is the ACL's name (acl->name), "src" is the
|
|
|
|
ACL keyword defining the matching method (acl_expr->kw) and the IP addresses
|
|
|
|
are patterns of type acl_pattern to match against the source address.
|
|
|
|
|
|
|
|
The acl_pattern struct may define one single pattern, a range of values or a
|
|
|
|
tree of values to match against. The type of the patterns is implied by the
|
|
|
|
ACL keyword. For instance, the "src" keyword implies IPv4 patterns.
|
|
|
|
|
|
|
|
The line above constitutes an ACL expression (acl_expr). ACL expressions are
|
|
|
|
formed of a keyword, an optional argument for the keyword, and a list of
|
|
|
|
patterns (in fact, both a list and a root tree).
|
|
|
|
|
|
|
|
Dynamic values are extracted according to a fetch function defined by the ACL
|
|
|
|
keyword. This fetch function fills or updates a struct acl_test with all the
|
|
|
|
extracted information so that a match function can compare it against all the
|
|
|
|
patterns. The fetch function is called iteratively by the ACL engine until it
|
|
|
|
reports no more value. This makes sense for instance when checking IP addresses
|
|
|
|
found in HTTP headers, which can appear multiple times. The acl_test is kept
|
|
|
|
intact between calls and even holds a context so that the fetch function knows
|
|
|
|
where to start from for subsequent calls. The match function may also use the
|
2021-01-08 04:24:41 +00:00
|
|
|
context even though it was not designed for that purpose.
|
2011-12-16 20:51:00 +00:00
|
|
|
|
|
|
|
An ACL is defined only by its name and can be a series of ACL expressions. The
|
|
|
|
ACL is deemed true when any of its expressions is true. They are evaluated in
|
|
|
|
the declared order and can involve multiple matching methods.
|
|
|
|
|
|
|
|
So in summary :
|
|
|
|
|
|
|
|
- an ACL is a series of tests to perform on a stream, any of which is enough
|
|
|
|
to validate the result.
|
2021-01-08 04:24:41 +00:00
|
|
|
|
2011-12-16 20:51:00 +00:00
|
|
|
- each test is defined by an expression associating a keyword and a series of
|
|
|
|
patterns.
|
|
|
|
|
|
|
|
- a keyword implies several things at once :
|
|
|
|
- the type of the patterns and how to parse them
|
|
|
|
- the method to fetch the required information from the stream
|
|
|
|
- the method to match the fetched information against the patterns
|
|
|
|
|
|
|
|
- a fetch function fills an acl_test struct which is passed to the match
|
|
|
|
function defined by the keyword
|
|
|
|
|
|
|
|
- the match function tries to match the value in the acl_test against the
|
|
|
|
pattern list declared in the expression which involved its acl_keyword.
|
|
|
|
|
|
|
|
|
|
|
|
ACLs are used by conditional processing rules. A rule generally uses an "if" or
|
|
|
|
"unless" keyword followed by an ACL condition (acl_cond). This condition is a
|
|
|
|
series of term suites which are ORed together. Each term suite is a series of
|
|
|
|
terms which are ANDed together. Terms may be negated before being evaluated in
|
|
|
|
a suite. A term simply is a pointer to an ACL.
|
|
|
|
|
|
|
|
We could then represent a rule by the following BNF :
|
|
|
|
|
2021-01-08 04:24:41 +00:00
|
|
|
rule = if-cond
|
2011-12-16 20:51:00 +00:00
|
|
|
| unless-cond
|
|
|
|
|
|
|
|
if-cond (struct acl_cond with ->pol = ACL_COND_IF)
|
|
|
|
= "if" condition
|
|
|
|
|
|
|
|
unless-cond (struct acl_cond with ->pol = ACL_COND_UNLESS)
|
|
|
|
= "unless" condition
|
|
|
|
|
|
|
|
condition
|
|
|
|
= term-suite
|
|
|
|
| term-suite "||" term-suite
|
|
|
|
| term-suite "or" term-suite
|
|
|
|
|
|
|
|
term-suite (struct acl_term_suite)
|
|
|
|
= term
|
|
|
|
| term term
|
|
|
|
|
|
|
|
term = acl
|
|
|
|
| "!" acl
|
|
|
|
|