I've fallen into a Hefferlump Trap with IPFilter. I am,
I must admit, doing some slightly odd things with my set
of rules; but I'd like to poll opinions about the best
way to proceed. So: let's explain how I wandered into
the Hefferlump Trap.
I have two constructs I have used successfully. One is:
block in quick <outer-condition> head 10000
pass in <inner-condition-1> group 10000
pass in <inner-condition-2> group 10000
pass in <inner-condition-3> group 10000
other rules with other <outer-conditions>
this being used, for example, with <outer-condition> selecting
a block of IP numbers with a particular policy and the <inner-
conditions> selecting all the traffic (by protocol and port
number) that are specifically allowed by that policy. The "trick"
is that group 10000 is "evaluated" after the <outer-condition>
has been tested but before the rule is tested for a "quick" tag.
The net effect is that the "block quick" is overridden if any
of the <inner-conditions> match successfully.
The other construct is an attempt to write a logical-or
condition. (I'd initially tried to use different rules to
test the various conditions and "call" the same group on
each rule, but that wasn't allowed.) So I came up with:
skip 3 in <condition-1>
skip 2 in <condition-2>
skip 1 in <condition-3>
skip 1 in all
pass in all head 20000
more rules to be executed in either case
to "call" group 20000 on any of the two conditions.
So far so good.
The trap was sprung when I tried to combine them. I wrote
a set of rules like:
block in quick <outer-condition> head 10000
skip 3 in <inner-condition-1> group 10000
skip 2 in <inner-condition-2> group 10000
skip 1 in <inner-condition-3> group 10000
skip 1 in all group 10000
pass in all head 20000 group 10000
more skipping "or" conditions calling other rule groups
and was very puzz;ed when it didn't work.
The problem is that the exact effects are non-obvious.
The way the code is written is that the rules are scanned
with code that looks like this pseudo-code:
skip_count = 0; pass_flags = PASS /* or FAIL! */
for (get first rule, if there is a rule, move to next rule) {
if (skip_count) { skip_count--; continue };
if (test_match_part_1_fails) continue;
if (test_match_part_2_fails) continue;
/* all parts of the rule condition match the packet here */
if (rule is a skip-rule) {
skip_count = count_from_the_rule;
} else {
pass_flags = flags_from_the_rule; /* PASS or FAIL including QUICK and other
flags */
}
if (rule is a head rule) {
pass_flags = recursive_call_the_function(pass_flags, other_parameters);
}
if (pass_flags && QUICKflag) {
break;
}
}
which explains how the "trick" is use in my first construct.
Further inspection also shows why my composite example fails:
as soon as one of the "skip" rules matches, the last test, on
the QUICK flag, which controls the "break" out of the for-loop,
succeeds and the "break" is taken. However, the QUICK flag that
causes this is the on from (in my example) the "block in quick"
line that is the "head" rule for group 10000; hence my confusion.
I'd like to poll opinions about what might be done. As I see it
the possibilities are:
1) Do nothing to the code and work out how to change my rule-set
2) Modify the code so that the "quick" flag is not tested for
on rules that do not update the "pass_flags" variable
3) Modify the code so that flags like the "quick" flag is
saved and restored through the recursive call; although
that will stop my first "trick" from working it might
make the rules more understandable in general
There is, of course, one opinion that matters more than the
others ;-) so if Darren would like to comment I'd be *most*
interested in his opinions; especially about any possible
code-changes.
--
David Pick