Re: pf: honor quick on anchor rules

2018-10-16 Thread mk-f
I tested the diff and while im not qualified to judge the code, it now behaves
like i would expect.

Thanks for working on this,
Regards.
 
> Klemens Nanni  hat am 16. Oktober 2018 um 13:34 geschrieben:
> 
> 
> On Tue, Oct 16, 2018 at 10:03:01AM +0200, Alexandr Nedvedicky wrote:
> > I also wonder if we should apply same change to wildcard anchors here:
> They need fixing as well, but I have yet to look into it.
> 
> > diff --git a/sys/net/pf.c b/sys/net/pf.c
> > index 0bdf90a8d13..5a5c739773a 100644
> > --- a/sys/net/pf.c
> > +++ b/sys/net/pf.c
> > @@ -3129,10 +3129,32 @@ pf_step_into_anchor(struct pf_test_ctx *ctx, struct 
> > pf_rule *r)
> > } else {
> > rv = pf_match_rule(ctx, &r->anchor->ruleset);
> This comment is way too much, imho. How about this:
> 
>   Unless errors occured, stop iff any rule matched
>   within quick anchors.
> 
> It's dense but we're inside pf_step_into_anchor() so context is given
> while the condition speaks for itself as well. I'd like to leave
> detailed explanations to the manual.
> 
> > -   if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK)
> > +   if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK &&
> > +   *ctx->am == r)
> > rv = PF_TEST_QUICK;
> > }
> That makes sense and works as expected with *all* examples and real use
> cases I could come up with.
> 
> Index: net/pf.c
> ===
> RCS file: /cvs/src/sys/net/pf.c,v
> retrieving revision 1.1076
> diff -u -p -r1.1076 pf.c
> --- net/pf.c  4 Oct 2018 20:25:59 -   1.1076
> +++ net/pf.c  16 Oct 2018 11:32:10 -
> @@ -3129,10 +3129,11 @@ pf_step_into_anchor(struct pf_test_ctx *
>   } else {
>   rv = pf_match_rule(ctx, &r->anchor->ruleset);
>   /*
> -  * Unless there was an error inside the anchor,
> -  * retain its quick state.
> +  * Unless errors occured, stop iff any rule matched
> +  * within quick anchors.
>*/
> - if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK)
> + if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK &&
> + *ctx->am == r)
>   rv = PF_TEST_QUICK;
>   }
>  
>



Re: pf: honor quick on anchor rules

2018-10-16 Thread Alexandr Nedvedicky
Hello,

> This comment is way too much, imho. How about this:
> 
>   Unless errors occured, stop iff any rule matched
>   within quick anchors.

I'm fine with your proposal. You have my OK to commit
the fix.

thanks and
regards
sashan



Re: pf: honor quick on anchor rules

2018-10-16 Thread Klemens Nanni
On Tue, Oct 16, 2018 at 10:03:01AM +0200, Alexandr Nedvedicky wrote:
> I also wonder if we should apply same change to wildcard anchors here:
They need fixing as well, but I have yet to look into it.

> diff --git a/sys/net/pf.c b/sys/net/pf.c
> index 0bdf90a8d13..5a5c739773a 100644
> --- a/sys/net/pf.c
> +++ b/sys/net/pf.c
> @@ -3129,10 +3129,32 @@ pf_step_into_anchor(struct pf_test_ctx *ctx, struct 
> pf_rule *r)
>   } else {
>   rv = pf_match_rule(ctx, &r->anchor->ruleset);
This comment is way too much, imho. How about this:

Unless errors occured, stop iff any rule matched
within quick anchors.

It's dense but we're inside pf_step_into_anchor() so context is given
while the condition speaks for itself as well. I'd like to leave
detailed explanations to the manual.

> - if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK)
> + if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK &&
> + *ctx->am == r)
>   rv = PF_TEST_QUICK;
>   }
That makes sense and works as expected with *all* examples and real use
cases I could come up with.

Index: net/pf.c
===
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.1076
diff -u -p -r1.1076 pf.c
--- net/pf.c4 Oct 2018 20:25:59 -   1.1076
+++ net/pf.c16 Oct 2018 11:32:10 -
@@ -3129,10 +3129,11 @@ pf_step_into_anchor(struct pf_test_ctx *
} else {
rv = pf_match_rule(ctx, &r->anchor->ruleset);
/*
-* Unless there was an error inside the anchor,
-* retain its quick state.
+* Unless errors occured, stop iff any rule matched
+* within quick anchors.
 */
-   if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK)
+   if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK &&
+   *ctx->am == r)
rv = PF_TEST_QUICK;
}
 



Re: pf: honor quick on anchor rules

2018-10-16 Thread Alexandr Nedvedicky
Hello,


> 
> In my understanding they do, but you are missing the point. Given the
> following ruleset:
> 
> pass
> anchor quick {
>   block inet6
> }
> block
> 
> With the current fix ruleset-evaluation terminates after the anchor,
> before the last block even *if no ipv6-traffic was encountered*. That is,
> no rule inside the (not empty) anchor matched, but evaluation is stopped
> nevertheless.
> 
> On 6.1 the anchor is ignored if no rule inside matches and evaluation
> continues, and that is what the original commit-log states:
> 

now I got it (I think). Klemens also made similar point off-list.
So with your help I could come to diff below. Which should hopefully
fix the bug you found. 

I also wonder if we should apply same change to wildcard anchors here:
3103 enum pf_test_status
3104 pf_step_into_anchor(struct pf_test_ctx *ctx, struct pf_rule *r)
3105 {

3118 RB_FOREACH(child, pf_anchor_node, &r->anchor->children) {
3119 rv = pf_match_rule(ctx, &child->ruleset);
3120 if ((rv == PF_TEST_QUICK) || (rv == PF_TEST_FAIL)) {
3121 /*
3122  * we either hit a rule with quick action
3123  * (more likely), or hit some runtime
3124  * error (e.g. pool_get() failure).
3125  */
3126 break;
3127 }

thanks and
regards
sashan

8<---8<---8<--8<
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 0bdf90a8d13..5a5c739773a 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -3129,10 +3129,32 @@ pf_step_into_anchor(struct pf_test_ctx *ctx, struct 
pf_rule *r)
} else {
rv = pf_match_rule(ctx, &r->anchor->ruleset);
/*
-* Unless there was an error inside the anchor,
-* retain its quick state.
+* Handle the 'anchor quick' case. Consider rules as follows:
+*
+*  pass all
+*  anchor quick {
+*  pass inet6
+*  }
+*  block all
+*
+* According to specification in pf.conf(5), the rules above
+* should block everything except IPv6 traffic. Rules above
+* should be read as follows:
+*
+*  if packet does not match any rule in anchor, then PF
+*  continues to process rules. The next rule after anchor
+*  is block, thus packet, which does not match 'pass
+*  inet6', gets blocked. On the other hand if particular
+*  packet matches 'pass inet6' rule, the 'quick' option
+*  kicks in and 'block all' is never reached. Such packet
+*  is allowed.
+*
+* If there was no error and we deal with 'anchor quick' and
+* there was a rule, which matched the packet, then we must
+* honor the 'quick' option to terminate rule processing.
 */
-   if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK)
+   if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK &&
+   *ctx->am == r)
rv = PF_TEST_QUICK;
}
 



Re: pf: honor quick on anchor rules

2018-10-15 Thread Fabian Mueller-Knapp
On 18-10-15 23:45:58, Alexandr Nedvedicky wrote:
> Hello,
> 
> > That is still different from the original (2006) behaviour which
> > would terminate ruleset-evaluation IFF any rules inside the anchor
> > actually match. 
> 
> Perhaps I still misunderstand the whole anchor thing.
> 
> let me clarify the proposed change by two examples. Ruleset below allows
> new connection because pass rule matches in 'anchor quick' block (the
> 'block all' rule is never reached).
> 
>   pass all
>   anchor quick {
>   pass all
>   }
>   block all
> 
> ruleset below does not allow connection, because the 'anchor quick' is
> empty. As such it does not match packet, therefore the whole anchor does
> not match, thus 'quick' does not count. PF continues to apply rules. It
> finds 'block all' for packet in question. Packet is blocked and game
> is over, the connection attempt times out.
> 
>   pass all
>   anchor quick {
>   }
>   block all
> 
> Do those two examples follow the behavior described in pf.conf(5) or not?
> if not what is the expected behavior for those two simple rulesets?

In my understanding they do, but you are missing the point. Given the
following ruleset:

pass
anchor quick {
block inet6
}
block

With the current fix ruleset-evaluation terminates after the anchor,
before the last block even *if no ipv6-traffic was encountered*. That is,
no rule inside the (not empty) anchor matched, but evaluation is stopped
nevertheless.

On 6.1 the anchor is ignored if no rule inside matches and evaluation
continues, and that is what the original commit-log states:

>>   Allow the 'quick' keyword on an anchor. IFF there is a matching 
>> rule inside
>>   the anchor, terminate ruleset evaluation when stepping out of the 
>> anchor.
>>
>>   This means that if you absolutely want the anchor to be terminal, 
>> you
>>   probably want to use a 'block all' or 'pass all' rule at the start 
>> of the
>>   anchor.

> 
> thanks a lot for your help
> regards
> sashan 

Regards
Fabian



Re: pf: honor quick on anchor rules

2018-10-15 Thread Alexandr Nedvedicky
Hello,

> That is still different from the original (2006) behaviour which
> would terminate ruleset-evaluation IFF any rules inside the anchor
> actually match. 

Perhaps I still misunderstand the whole anchor thing.

let me clarify the proposed change by two examples. Ruleset below allows
new connection because pass rule matches in 'anchor quick' block (the
'block all' rule is never reached).

pass all
anchor quick {
pass all
}
block all

ruleset below does not allow connection, because the 'anchor quick' is
empty. As such it does not match packet, therefore the whole anchor does
not match, thus 'quick' does not count. PF continues to apply rules. It
finds 'block all' for packet in question. Packet is blocked and game
is over, the connection attempt times out.

pass all
anchor quick {
}
block all

Do those two examples follow the behavior described in pf.conf(5) or not?
if not what is the expected behavior for those two simple rulesets?

thanks a lot for your help
regards
sashan 



Re: pf: honor quick on anchor rules

2018-10-15 Thread Fabian Mueller-Knapp
On 18-10-15 13:38:32, Alexandr Nedvedicky wrote:
> Hello,
> 
> I just got back on-line after a week. Thank you all for detailed analysis.
> This particular bug, which Klemens tries to fix is caused by my commit 1.1024:
> 
> - percpu anchor stacks
>   we actually don't need to pre-allocate per_anchor_stack[], if we use
>   a 'natural' recursion, when doing anchor tree traversal.
> 
> Diff below fixes the case reported by Fabian:
> 
> > snap# uname -a
> > OpenBSD snap.my.domain 6.4 GENERIC#333 amd64
> > snap# pfctl -sr 
> >
> > pass all flags S/SA
> > anchor quick all {
> > }
> > block drop all
> > 
> 
> The idea is to override 'anchor quick' for empty rulesets. If the particular
> anchor, which pf_step_into_anchor() is about to enter, is empty, then the
> pf_step_into_anchor() bails out immediately with PF_TEST_OK result to keep
> PF processing the rules. I think this was the missing piece in mosaic.

That is still different from the original (2006) behaviour which
would terminate ruleset-evaluation IFF any rules inside the anchor
actually match. 

> 
> OK ?
> 
> sorry for inconveniences
> regards
> sashan
> 
> 8<---8<---8<--8<
> diff --git a/sys/net/pf.c b/sys/net/pf.c
> index 0bdf90a8d13..72841c9b8f0 100644
> --- a/sys/net/pf.c
> +++ b/sys/net/pf.c
> @@ -3126,7 +3126,7 @@ pf_step_into_anchor(struct pf_test_ctx *ctx, struct 
> pf_rule *r)
>   break;
>   }
>   }
> - } else {
> + } else if (!TAILQ_EMPTY(r->anchor->ruleset.rules.active.ptr)) {
>   rv = pf_match_rule(ctx, &r->anchor->ruleset);
>   /*
>* Unless there was an error inside the anchor,
> @@ -3134,7 +3134,8 @@ pf_step_into_anchor(struct pf_test_ctx *ctx, struct 
> pf_rule *r)
>*/
>   if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK)
>   rv = PF_TEST_QUICK;
> - }
> + } else
> + rv = PF_TEST_OK;
>  
>   ctx->depth--;
>  



Re: pf: honor quick on anchor rules

2018-10-15 Thread Alexandr Nedvedicky
Hello,

I just got back on-line after a week. Thank you all for detailed analysis.
This particular bug, which Klemens tries to fix is caused by my commit 1.1024:

- percpu anchor stacks
  we actually don't need to pre-allocate per_anchor_stack[], if we use
  a 'natural' recursion, when doing anchor tree traversal.

Diff below fixes the case reported by Fabian:

> snap# uname -a
> OpenBSD snap.my.domain 6.4 GENERIC#333 amd64
> snap# pfctl -sr   
>  
> pass all flags S/SA
> anchor quick all {
> }
> block drop all
> 

The idea is to override 'anchor quick' for empty rulesets. If the particular
anchor, which pf_step_into_anchor() is about to enter, is empty, then the
pf_step_into_anchor() bails out immediately with PF_TEST_OK result to keep
PF processing the rules. I think this was the missing piece in mosaic.

OK ?

sorry for inconveniences
regards
sashan

8<---8<---8<--8<
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 0bdf90a8d13..72841c9b8f0 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -3126,7 +3126,7 @@ pf_step_into_anchor(struct pf_test_ctx *ctx, struct 
pf_rule *r)
break;
}
}
-   } else {
+   } else if (!TAILQ_EMPTY(r->anchor->ruleset.rules.active.ptr)) {
rv = pf_match_rule(ctx, &r->anchor->ruleset);
/*
 * Unless there was an error inside the anchor,
@@ -3134,7 +3134,8 @@ pf_step_into_anchor(struct pf_test_ctx *ctx, struct 
pf_rule *r)
 */
if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK)
rv = PF_TEST_QUICK;
-   }
+   } else
+   rv = PF_TEST_OK;
 
ctx->depth--;
 



Re: pf: honor quick on anchor rules

2018-10-08 Thread Sebastian Benoit
Henning Brauer(hb-openbsdt...@ml.bsws.de) on 2018.10.08 13:56:20 +0200:
> * Sebastian Benoit  [2018-10-08 10:50]:
> > The quick in the anchor does not do anything by itself, it should just
> > "behave like all the rules inside the anchor had the quick keyword".
> 
> no, that is *not* the intended semantic.
> the intent is that ruleset evaluation is aborted if any rule inside
> the anchor matched. note that this is very different from "any rule
> inside treated like it had quick", since that would abort evaluation
> *inside* the anchor immediately as well.

yes, i simplified it too much, thanks



Re: pf: honor quick on anchor rules

2018-10-08 Thread Henning Brauer
* Sebastian Benoit  [2018-10-08 10:50]:
> The quick in the anchor does not do anything by itself, it should just
> "behave like all the rules inside the anchor had the quick keyword".

no, that is *not* the intended semantic.
the intent is that ruleset evaluation is aborted if any rule inside
the anchor matched. note that this is very different from "any rule
inside treated like it had quick", since that would abort evaluation
*inside* the anchor immediately as well.

-- 
Henning Brauer, h...@bsws.de, henn...@openbsd.org
BS Web Services GmbH, http://bsws.de, Full-Service ISP
Secure Hosting, Mail and DNS. Virtual & Dedicated Servers, Root to Fully Managed
Henning Brauer Consulting, http://henningbrauer.com/



Re: pf: honor quick on anchor rules

2018-10-08 Thread Sebastian Benoit
Klemens Nanni(k...@openbsd.org) on 2018.10.07 19:41:22 +0200:
> On Fri, Oct 05, 2018 at 11:53:08PM +0200, Klemens Nanni wrote:
> > On Fri, Oct 05, 2018 at 10:38:48PM +0200, Fabian Mueller-Knapp wrote:
> > > If i read man correctly it means "evaluate the rules inside and stop if
> > > any rule within matched".
> > While it's own description is quite clear and unambigious:
> > 
> >  quick   If a packet matches a rule which has the quick option set, this
> >  rule is considered the last matching rule, and evaluation of
> >  subsequent rules is skipped.
> > 
> > the anchor specific addition can be improved indeed:
> > 
> >  If the anchor itself is marked with the quick option, ruleset
> >  evaluation will terminate when the anchor is exited if the packet is
> >  matched by any rule within the anchor.
> > 
> > Does an empty ruleset match a packet? If so, and our code technically
> > does so, -current including my latest fix behaves correctly according
> > to the documentation.
> Admittedly, I should have read the second paragraph more carefully.
> 
> > > With the current fix, rule evaluation stops after the first block,
> > > regardless of matching. Therefore the following currently always passes: 
> > > 
> > > snap# uname -a
> > > OpenBSD snap.my.domain 6.4 GENERIC#333 amd64
> > > snap# pfctl -sr   
> > >  
> > > pass all flags S/SA
> > > anchor quick all {
> > > }
> > > block drop all
> > > 
> > > 6.1 behaves as i would expect, it drops all. Instead of the empty block,
> > > any non-matching rule has the same effect.
> > While rules within the anchor do not match, the anchor itself does.
> > After all, it is a rule itself just like `pass' or `block', hence your
> > ruleset's second rule `anchor quick' matches every packet and therefore
> > stops evaluation.
> When mcbride introduced `anchor quick' back in 2006 it was indeed bound
> to matches within the ruleset:
> 
>   commit a81eb4e4f7ac27afb4708cf434aee361f1ef8b19
>   Author: mcbride 
>   Date:   Wed Oct 11 08:42:31 2006 +
> 
>   Allow the 'quick' keyword on an anchor. IFF there is a matching 
> rule inside
>   the anchor, terminate ruleset evaluation when stepping out of the 
> anchor.
> 
>   This means that if you absolutely want the anchor to be terminal, 
> you
>   probably want to use a 'block all' or 'pass all' rule at the start 
> of the
>   anchor.
> 
>   ok dhartmei@ henning@ deraadt@
> 
> Digging through commits and the history of PF already takes more of my
> time than I anticipated. Some time after 2006, or more specifically
> after 6.1 being released, this behaviour got broken^Wchanged - most
> likely unintionally.
> 
> Since our code now treats `anchor quick' like any other normal rule
> (see my other reply to benno in this thread), I suggest we adjust our
> documentation so users will not fall for it again.
> 
> Fixing^Wchaning this behaviour is debatable but should probably not
> happen before 6.4 comes out anyway, so I suggest we better ship with
> a correct manual.
> 
> Feedback? OK?

I think the current behaviour is wrong and the original from 2006 correct.
I think it should do what the above commit message (and the manpage) says.

The quick in the anchor does not do anything by itself, it should just
"behave like all the rules inside the anchor had the quick keyword".


> We might as well remove the entire sentence to not special case anchors
> at all anymore.
> 
> Index: pf.conf.5
> ===
> RCS file: /cvs/src/share/man/man5/pf.conf.5,v
> retrieving revision 1.577
> diff -u -p -r1.577 pf.conf.5
> --- pf.conf.5 12 Jul 2018 05:54:49 -  1.577
> +++ pf.conf.5 7 Oct 2018 17:40:07 -
> @@ -1865,8 +1865,7 @@ anchors and the main ruleset.
>  If the anchor itself is marked with the
>  .Cm quick
>  option,
> -ruleset evaluation will terminate when the anchor is exited if the packet is
> -matched by any rule within the anchor.
> +ruleset evaluation will terminate when the anchor is exited.
>  .Pp
>  An anchor references other anchor attachment points
>  using the following syntax:
> 



Re: pf: honor quick on anchor rules

2018-10-07 Thread Klemens Nanni
On Fri, Oct 05, 2018 at 11:53:08PM +0200, Klemens Nanni wrote:
> On Fri, Oct 05, 2018 at 10:38:48PM +0200, Fabian Mueller-Knapp wrote:
> > If i read man correctly it means "evaluate the rules inside and stop if
> > any rule within matched".
> While it's own description is quite clear and unambigious:
> 
>  quick   If a packet matches a rule which has the quick option set, this
>  rule is considered the last matching rule, and evaluation of
>  subsequent rules is skipped.
> 
> the anchor specific addition can be improved indeed:
> 
>  If the anchor itself is marked with the quick option, ruleset
>  evaluation will terminate when the anchor is exited if the packet is
>  matched by any rule within the anchor.
> 
> Does an empty ruleset match a packet? If so, and our code technically
> does so, -current including my latest fix behaves correctly according
> to the documentation.
Admittedly, I should have read the second paragraph more carefully.

> > With the current fix, rule evaluation stops after the first block,
> > regardless of matching. Therefore the following currently always passes: 
> > 
> > snap# uname -a
> > OpenBSD snap.my.domain 6.4 GENERIC#333 amd64
> > snap# pfctl -sr 
> >
> > pass all flags S/SA
> > anchor quick all {
> > }
> > block drop all
> > 
> > 6.1 behaves as i would expect, it drops all. Instead of the empty block,
> > any non-matching rule has the same effect.
> While rules within the anchor do not match, the anchor itself does.
> After all, it is a rule itself just like `pass' or `block', hence your
> ruleset's second rule `anchor quick' matches every packet and therefore
> stops evaluation.
When mcbride introduced `anchor quick' back in 2006 it was indeed bound
to matches within the ruleset:

commit a81eb4e4f7ac27afb4708cf434aee361f1ef8b19
Author: mcbride 
Date:   Wed Oct 11 08:42:31 2006 +

Allow the 'quick' keyword on an anchor. IFF there is a matching 
rule inside
the anchor, terminate ruleset evaluation when stepping out of the 
anchor.

This means that if you absolutely want the anchor to be terminal, 
you
probably want to use a 'block all' or 'pass all' rule at the start 
of the
anchor.

ok dhartmei@ henning@ deraadt@

Digging through commits and the history of PF already takes more of my
time than I anticipated. Some time after 2006, or more specifically
after 6.1 being released, this behaviour got broken^Wchanged - most
likely unintionally.

Since our code now treats `anchor quick' like any other normal rule
(see my other reply to benno in this thread), I suggest we adjust our
documentation so users will not fall for it again.

Fixing^Wchaning this behaviour is debatable but should probably not
happen before 6.4 comes out anyway, so I suggest we better ship with
a correct manual.

Feedback? OK?

We might as well remove the entire sentence to not special case anchors
at all anymore.

Index: pf.conf.5
===
RCS file: /cvs/src/share/man/man5/pf.conf.5,v
retrieving revision 1.577
diff -u -p -r1.577 pf.conf.5
--- pf.conf.5   12 Jul 2018 05:54:49 -  1.577
+++ pf.conf.5   7 Oct 2018 17:40:07 -
@@ -1865,8 +1865,7 @@ anchors and the main ruleset.
 If the anchor itself is marked with the
 .Cm quick
 option,
-ruleset evaluation will terminate when the anchor is exited if the packet is
-matched by any rule within the anchor.
+ruleset evaluation will terminate when the anchor is exited.
 .Pp
 An anchor references other anchor attachment points
 using the following syntax:



Re: pf: honor quick on anchor rules

2018-10-06 Thread Klemens Nanni
On Sat, Oct 06, 2018 at 01:07:33PM +0200, Sebastian Benoit wrote:
> I would find it surprising if an empty anchor matches anything.
> And i find the wording above clear in this regard:
> 
>   ... ruleset evaluation will terminate when the anchor is exited if
>   the packet is matched by any rule within the anchor.
> 
> If there is no rule in the anchor, then there is no match, so the quick
> should do nothing.
You are wrong. Matches *within* are different from matching on the
anchor itself:

# echo anchor a quick | pfctl -vf-
anchor "a" quick all

All packets match this anchor, as made clear by `all'. Think
s/anchor "a"/pass/ here if you will, doesn't make a difference. Further
adding rules to the anchor "a" can change it's outcome, though:

# echo block inet | pfctl -aa -f-
# pfctl -sr -a\*
anchor "a" quick all {
  block drop inet all
}

So now you just block IPv4, but still pass everything else.

This is perfectly valid. Thinking about it once more, we really cannot
special-case anchors (with empty rulesets). Taking above example into
account, should the anchor disappear and magically change your loaded
ruleset once it's cleared? It does not make any sense and would break
lots of real use cases.

Again: daemons rely on this behaviour, see relayd(8) which must interact
with PF through a previously defined anchor:

anchor "relayd/*"

Where this anchor is placed is up to the user and so is it's content.
There is nothing that stops you from doing

anchor "relayd/*" inet6

to ignore IPv4 traffic through relayd or other crazy things. Messing
with how anchors are treated (they are really just normal rules) is a
bad idea.

This should somewhat answer your question as well, Theo.



Re: pf: honor quick on anchor rules

2018-10-06 Thread Sebastian Benoit
Klemens Nanni(k...@openbsd.org) on 2018.10.05 23:53:08 +0200:
> On Fri, Oct 05, 2018 at 10:38:48PM +0200, Fabian Mueller-Knapp wrote:
> > If i read man correctly it means "evaluate the rules inside and stop if
> > any rule within matched".
> While it's own description is quite clear and unambigious:
> 
>  quick   If a packet matches a rule which has the quick option set, this
>  rule is considered the last matching rule, and evaluation of
>  subsequent rules is skipped.
> 
> the anchor specific addition can be improved indeed:
> 
>  If the anchor itself is marked with the quick option, ruleset
>  evaluation will terminate when the anchor is exited if the packet is
>  matched by any rule within the anchor.
> 
> Does an empty ruleset match a packet? If so, and our code technically

I would find it surprising if an empty anchor matches anything.
And i find the wording above clear in this regard:

... ruleset evaluation will terminate when the anchor is exited if
the packet is matched by any rule within the anchor.

If there is no rule in the anchor, then there is no match, so the quick
should do nothing.

> does so, -current including my latest fix behaves correctly according
> to the documentation.
> 
> > With the current fix, rule evaluation stops after the first block,
> > regardless of matching. Therefore the following currently always passes: 
> > 
> > snap# uname -a
> > OpenBSD snap.my.domain 6.4 GENERIC#333 amd64
> > snap# pfctl -sr 
> >
> > pass all flags S/SA
> > anchor quick all {
> > }
> > block drop all
> > 
> > 6.1 behaves as i would expect, it drops all. Instead of the empty block,
> > any non-matching rule has the same effect.
> While rules within the anchor do not match, the anchor itself does.
> After all, it is a rule itself just like `pass' or `block', hence your
> ruleset's second rule `anchor quick' matches every packet and therefore
> stops evaluation.
> 



Re: pf: honor quick on anchor rules

2018-10-05 Thread Theo de Raadt
Klemens Nanni  wrote:

> On Fri, Oct 05, 2018 at 11:53:08PM +0200, Klemens Nanni wrote:
> > While rules within the anchor do not match, the anchor itself does.
> > After all, it is a rule itself just like `pass' or `block', hence your
> > ruleset's second rule `anchor quick' matches every packet and therefore
> > stops evaluation.
> To illustrate further:
> 
> Block everything except IPv4 traffic:
> 
>   pass
>   anchor quick inet {
>   }
>   block
> 
> This very bad example is stupid but works as expected. It's especially
> bad as it uses an anonymous anchor, thus you cannot modify it later on
> using `pfctl -a ...'.
> 
> Maybe we should disallow anonymous anchors with empty rulesets for above
> mentioned reasons?

I don't understand why to disallow it.  It is quirky, but does as
expected.  Why does one need to be able to modify it?  anchors grew
into what you see now, the initial design was an attempt to beat skip-step
performance by giving the rule-writer more control.  But then the optimizer
showed up...



Re: pf: honor quick on anchor rules

2018-10-05 Thread Klemens Nanni
On Fri, Oct 05, 2018 at 11:53:08PM +0200, Klemens Nanni wrote:
> While rules within the anchor do not match, the anchor itself does.
> After all, it is a rule itself just like `pass' or `block', hence your
> ruleset's second rule `anchor quick' matches every packet and therefore
> stops evaluation.
To illustrate further:

Block everything except IPv4 traffic:

pass
anchor quick inet {
}
block

This very bad example is stupid but works as expected. It's especially
bad as it uses an anonymous anchor, thus you cannot modify it later on
using `pfctl -a ...'.

Maybe we should disallow anonymous anchors with empty rulesets for above
mentioned reasons?

Do note that named but empty anchors as fine and even neccessary for
some daemons such as relayd(8):

anchor "relayd/*"



Re: pf: honor quick on anchor rules

2018-10-05 Thread Klemens Nanni
On Fri, Oct 05, 2018 at 10:38:48PM +0200, Fabian Mueller-Knapp wrote:
> If i read man correctly it means "evaluate the rules inside and stop if
> any rule within matched".
While it's own description is quite clear and unambigious:

 quick   If a packet matches a rule which has the quick option set, this
 rule is considered the last matching rule, and evaluation of
 subsequent rules is skipped.

the anchor specific addition can be improved indeed:

 If the anchor itself is marked with the quick option, ruleset
 evaluation will terminate when the anchor is exited if the packet is
 matched by any rule within the anchor.

Does an empty ruleset match a packet? If so, and our code technically
does so, -current including my latest fix behaves correctly according
to the documentation.

> With the current fix, rule evaluation stops after the first block,
> regardless of matching. Therefore the following currently always passes: 
> 
> snap# uname -a
> OpenBSD snap.my.domain 6.4 GENERIC#333 amd64
> snap# pfctl -sr   
>  
> pass all flags S/SA
> anchor quick all {
> }
> block drop all
> 
> 6.1 behaves as i would expect, it drops all. Instead of the empty block,
> any non-matching rule has the same effect.
While rules within the anchor do not match, the anchor itself does.
After all, it is a rule itself just like `pass' or `block', hence your
ruleset's second rule `anchor quick' matches every packet and therefore
stops evaluation.



Re: pf: honor quick on anchor rules

2018-10-05 Thread Fabian Mueller-Knapp
Hello,

Sorry for the late reply. I just tested the fix with the latest snapshot
and think the behaviour is still not correct:

On 18-10-04 01:25:09, Klemens Nanni wrote:
> On Sat, Sep 29, 2018 at 10:44:41PM +0200, Klemens Nanni wrote:
> 
> `anchor quick' means "evaluate the rules inside but stop after that".

If i read man correctly it means "evaluate the rules inside and stop if
any rule within matched".

With the current fix, rule evaluation stops after the first block,
regardless of matching. Therefore the following currently always passes: 

snap# uname -a
OpenBSD snap.my.domain 6.4 GENERIC#333 amd64
snap# pfctl -sr
pass all flags S/SA
anchor quick all {
}
block drop all

6.1 behaves as i would expect, it drops all. Instead of the empty block,
any non-matching rule has the same effect.

Regards,
Fabian



Re: pf: honor quick on anchor rules

2018-10-04 Thread Klemens Nanni
I just committed the fix, thanks.



Re: pf: honor quick on anchor rules

2018-10-04 Thread Alexandr Nedvedicky
Hi Klemens,




> > > Do i misread the manpage somehow?
> > No, this is a bug.
> Allow me a bit of rubber ducking to explain this bug and ease review:
> 
> The kernel evaluates the ruleset pretty much like we read it: Down to
> bottom until quick appears or an error occurs in which case we stop
> evaluating. That is, packets are tested against each rule which yields
> either of OK, QUICK, FAIL.
> 
> `anchor quick' means "evaluate the rules inside but stop after that".
> According to the procedure explained above, an anchor rule's test status
> is the result of its contained ruleset:
> 
> sys/net/pf.c
> 3130  rv = pf_match_rule(ctx, &r->anchor->ruleset);
> 
> While this approach is valid for other type of rules, it overwrites the
> anchor rule's *own* QUICK test result such that it has no effect at all.
> To fix this, simply pass it along except when there was an error so we
> do not clobber it (and make the same mistake again).
> 
> 
> Feedback? OK?

thank you for cleaning up the mess I did create long time ago.
I agree with your change.

OK sashan



pf: honor quick on anchor rules

2018-10-03 Thread Klemens Nanni
On Sat, Sep 29, 2018 at 10:44:41PM +0200, Klemens Nanni wrote:
> On Sat, Sep 29, 2018 at 06:17:05PM +0200, Fabian Mueller-Knapp wrote:
> > I have the following pf.conf:
> > 
> > anchor quick {
> >   pass
> > }
> > block
> > 
> > # pfctl -sr
> > anchor quick all {
> >   pass all flags S/SA
> > }
> > block drop all
> > 
> > Because of the 'quick' i assumed, that 'block' is never reached, but it
> > is since 6.2.
> Indeed, `pfctl -s rules -v' clearly shows how every packet goes through
> all three rules.
> 
> > man pf.conf(5) states:
> > 
> > "If the anchor itself is marked with the quick option, ruleset
> > evaluation will terminate when the anchor is exited if the packet is
> > matched by any rule within the anchor."
> > 
> > I tested with fresh installs of 6.1, 6.2, 6.3 and current via vmd and
> > 6.1 does in fact behave as i would accept (that is, all packets
> > pass). From 6.2 on however, all packets are dropped.
> Thanks for your report.
> 
> > Do i misread the manpage somehow?
> No, this is a bug.
Allow me a bit of rubber ducking to explain this bug and ease review:

The kernel evaluates the ruleset pretty much like we read it: Down to
bottom until quick appears or an error occurs in which case we stop
evaluating. That is, packets are tested against each rule which yields
either of OK, QUICK, FAIL.

`anchor quick' means "evaluate the rules inside but stop after that".
According to the procedure explained above, an anchor rule's test status
is the result of its contained ruleset:

sys/net/pf.c
3130rv = pf_match_rule(ctx, &r->anchor->ruleset);

While this approach is valid for other type of rules, it overwrites the
anchor rule's *own* QUICK test result such that it has no effect at all.
To fix this, simply pass it along except when there was an error so we
do not clobber it (and make the same mistake again).


Feedback? OK?

Index: net/pf.c
===
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.1075
diff -u -p -r1.1075 pf.c
--- net/pf.c13 Sep 2018 19:53:58 -  1.1075
+++ net/pf.c3 Oct 2018 22:22:32 -
@@ -3128,6 +3128,12 @@ pf_step_into_anchor(struct pf_test_ctx *
}
} else {
rv = pf_match_rule(ctx, &r->anchor->ruleset);
+   /*
+* Unless there was an error inside the anchor,
+* retain its quick state.
+*/
+   if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK)
+   rv = PF_TEST_QUICK;
}
 
ctx->depth--;