Re: pf(4) schemantics

2003-03-21 Thread Henning Brauer
On Thu, Mar 20, 2003 at 09:01:22PM +0100, Srebrenko Sehic wrote:
 On Thu, Mar 20, 2003 at 12:32:50PM -0700, [EMAIL PROTECTED] wrote: 
  Okay, I think I'm starting to understand what you want. (because I
  believe we tossed the idea around at the last hackathon)
  Basically, you want a state-creating packet to be able to create state
  on multiple interfaces, like:
  pass in on $ext_if proto tcp from any to $webserver port 80 \
 keep state on {$ext_if $int_if} flags S/SAFR
  (The way I had envisioned it, this would only occur for the
  state-creating packet, and it would only do so for the interfaces
  indicated.)
  Is this what you mean?
 Yes, thank you. I also still mean that pf(4) should not care about
 packets going 'out' of an interface, only in, but let's kill this
 thread.

I'm close to give up on you wrt to that. SOmehow it seems you don't _want_
to see why the filtering outbond on an interface is so important. I gave a
very good example why that is absolutely needed.

 Or even better, dis the keep state on {$ext_if $int_if}; keep
 state should be enough, since pf(4) should take care of that.

no way.
see above.

 Now this feature would be _very_ nice.
 Any chance this could be implemented, say post 3.3?
 Henning? Others?

it would be keep state on { interface-list }, to make that clear.
I don't like the idea too much. I see _very_ little gain, but enough pain.

I mean, it's not knew. We talked about that during c2k2. That is a year ago
soon. If that idea had been so good we would have added it already, no? ;-)

-- 
Henning Brauer, BS Web Services, http://bsws.de
[EMAIL PROTECTED] - [EMAIL PROTECTED]
Unix is very simple, but it takes a genius to understand the simplicity.
(Dennis Ritchie)



Re: pf(4) schemantics

2003-03-21 Thread Philipp Buehler - sysfive.com GmbH
On 20/03/2003, Srebrenko Sehic [EMAIL PROTECTED] wrote To [EMAIL PROTECTED]:
 Or even better, dis the keep state on {$ext_if $int_if}; keep
 state should be enough, since pf(4) should take care of that. Now
 this feature would be _very_ nice.
 
 Any chance this could be implemented, say post 3.3?

Over my dead (and the really slacking) body.

This auto-generation of states on other interfaces is BRAINDEAD.
I do not even feel good about the 'on {if_list}', but well.

tons of ways to achieve that are 'out there' already, anyway.

It was a great relief, when I recognized that pf is NOT generating
states for all interfaces, and I am all against that this would change.

ciao
-- 
 Philipp Buehler  -  [EMAIL PROTECTED]  -  http://sysfive.com/
 sysfive.com GmbH - UNIX. Networking. Security. Applications.



Re: pf(4) schemantics

2003-03-21 Thread Srebrenko Sehic
On Thu, Mar 20, 2003 at 06:27:04PM -0800, Kyle R. Hofmann wrote:

 So far everyone who has responded to you has been polite, despite your
 inability to comprehend what they're telling you.  Now, in the proud
 tradition of OpenBSD lusers everywhere, I will flame you:

I don't recall _you_ being a part of the discussion.
So shut up flamer ;)



Re: pf(4) schemantics

2003-03-21 Thread Srebrenko Sehic
On Thu, Mar 20, 2003 at 04:13:04PM -0700, [EMAIL PROTECTED] wrote:

  I assume that 'pass out all keep state' makes pf(4), at least, do a
  state lookup in the table? AFAIK, that's, in worst case scenario, 16
  searches down the binary tree? That ought to eat a few cycles.

 I really doubt there is a performance issue here, or really, that this
 would be the bottleneck. If it is, show the facts, and we (I use the
 royal we here, meaning Daniel or Henning) can address it then.

Hmm? It might not be a major bottleneck, but keeping state for nothing
and on _two_ interfaces, must cost something. Let's not forget about
memory cost also.



Re: pf(4) schemantics

2003-03-21 Thread Srebrenko Sehic
On Fri, Mar 21, 2003 at 12:52:14PM +0100, Henning Brauer wrote:
 On Thu, Mar 20, 2003 at 11:16:10PM +0100, Srebrenko Sehic wrote:
  This is cosmetics. However, whouldn't we get some performance increase
  if pf(4) didn't bother looking at packets (in certain situations) going
  'out' at all?
 
 please show me where that tiny little state search is a problem in real world.

We want pf(4) to outperform those nifty FWSM/5Gbps firewall blades. No?
;)



Re: pf(4) schemantics

2003-03-21 Thread Srebrenko Sehic
On Fri, Mar 21, 2003 at 12:50:43PM +0100, Henning Brauer wrote:

 I'm close to give up on you wrt to that. SOmehow it seems you don't _want_
 to see why the filtering outbond on an interface is so important. I gave a
 very good example why that is absolutely needed.

Bla, bla, since traffic can originate from the firewall itself. In a lot of
cases, it doesn't, though.

 it would be keep state on { interface-list }, to make that clear.
 I don't like the idea too much. I see _very_ little gain, but enough pain.
 
 I mean, it's not knew. We talked about that during c2k2. That is a year ago
 soon. If that idea had been so good we would have added it already, no? ;-)

I'm sure you guys will make the right judgement. I'm just tossing ideas
around.



Re: pf(4) schemantics

2003-03-21 Thread Henning Brauer
On Fri, Mar 21, 2003 at 06:47:44PM +0100, Srebrenko Sehic wrote:
 On Fri, Mar 21, 2003 at 12:52:14PM +0100, Henning Brauer wrote:
  On Thu, Mar 20, 2003 at 11:16:10PM +0100, Srebrenko Sehic wrote:
   This is cosmetics. However, whouldn't we get some performance increase
   if pf(4) didn't bother looking at packets (in certain situations) going
   'out' at all?
  please show me where that tiny little state search is a problem in real world.
 We want pf(4) to outperform those nifty FWSM/5Gbps firewall blades. No?

chances are we do already?

why in hell do you think that THIS is the bottleneck, if at all?
where's your detailed performance analysis?



Re: pf(4) schemantics

2003-03-21 Thread Can Erkin Acar
On Fri, Mar 21, 2003 at 06:44:37PM +0100, Srebrenko Sehic wrote:
 On Fri, Mar 21, 2003 at 12:50:43PM +0100, Henning Brauer wrote:
 
  I'm close to give up on you wrt to that. SOmehow it seems you don't _want_
  to see why the filtering outbond on an interface is so important. I gave a
  very good example why that is absolutely needed.
 
 Bla, bla, since traffic can originate from the firewall itself. In a lot of
 cases, it doesn't, though.

Yeah, tell that to my OpenBSD web/file server and the desktop machine
from which I am writing this mail. I have great many reasons to filter BOTH
inbound and outbound traffic. And repeat after me: OpenBSD is NOT
just a firewall appliance. 

Also, there are MANY cases where filtering traffic originating from a firewall
is needed. Think about application level proxies for instance.

Can



Re: pf(4) schemantics

2003-03-21 Thread Henning Brauer
On Fri, Mar 21, 2003 at 06:44:37PM +0100, Srebrenko Sehic wrote:
 On Fri, Mar 21, 2003 at 12:50:43PM +0100, Henning Brauer wrote:
  I'm close to give up on you wrt to that. SOmehow it seems you don't _want_
  to see why the filtering outbond on an interface is so important. I gave a
  very good example why that is absolutely needed.
 Bla, bla, since traffic can originate from the firewall itself. In a lot of
 cases, it doesn't, though.

geez, get your facts straight.
traffic originates from your firewall, if you believe it or not. what about
returns, icmp, tcp ttl exceeded, dns lookups, ...

(yayayaya, ipless bridge, babble blubble babble gimmebeer)

-- 
Henning Brauer, BS Web Services, http://bsws.de
[EMAIL PROTECTED] - [EMAIL PROTECTED]
Unix is very simple, but it takes a genius to understand the simplicity.
(Dennis Ritchie)



Re: pf(4) schemantics

2003-03-20 Thread kjell

Okay, I think I'm starting to understand what you want. (because I
believe we tossed the idea around at the last hackathon)

Basically, you want a state-creating packet to be able to create state
on multiple interfaces, like:

pass in on $ext_if proto tcp from any to $webserver port 80 \
   keep state on {$ext_if $int_if} flags S/SAFR

(The way I had envisioned it, this would only occur for the
state-creating packet, and it would only do so for the interfaces
indicated.)

Is this what you mean?

-kj



Re: pf(4) schemantics

2003-03-20 Thread Srebrenko Sehic
On Thu, Mar 20, 2003 at 12:32:50PM -0700, [EMAIL PROTECTED] wrote:

 Okay, I think I'm starting to understand what you want. (because I
 believe we tossed the idea around at the last hackathon)
 
 Basically, you want a state-creating packet to be able to create state
 on multiple interfaces, like:
 
 pass in on $ext_if proto tcp from any to $webserver port 80 \
keep state on {$ext_if $int_if} flags S/SAFR
 
 (The way I had envisioned it, this would only occur for the
 state-creating packet, and it would only do so for the interfaces
 indicated.)
 
 Is this what you mean?

Yes, thank you. I also still mean that pf(4) should not care about
packets going 'out' of an interface, only in, but let's kill this
thread.

Or even better, dis the keep state on {$ext_if $int_if}; keep
state should be enough, since pf(4) should take care of that. Now
this feature would be _very_ nice.

Any chance this could be implemented, say post 3.3?

Henning? Others?



Re: pf(4) schemantics

2003-03-20 Thread kjell
 Yes, thank you. I also still mean that pf(4) should not care about
 packets going 'out' of an interface, only in, but let's kill this
 thread.

Again: traffic can originate on the firewall box. Since this traffic
never passes inbound on an interface, filtering MUST be done
on the outbound direction. (ie - transparent proxies).

-kj



Re: pf(4) schemantics

2003-03-20 Thread Srebrenko Sehic
On Thu, Mar 20, 2003 at 02:16:02PM -0700, [EMAIL PROTECTED] wrote:

 Again: traffic can originate on the firewall box. Since this traffic
 never passes inbound on an interface, filtering MUST be done
 on the outbound direction. (ie - transparent proxies).

Yes, but it could be nice if one could choose, eg.
set filter-policy {in, out, both} or something.



Re: pf(4) schemantics

2003-03-20 Thread kjell
 Yes, but it could be nice if one could choose, eg.
 set filter-policy {in, out, both} or something.

You can choose. Either type:

block out all

or

pass out all keep state

I do not understand this part of your argument at all.
-kj



Re: pf(4) schemantics

2003-03-20 Thread kjell

 This is cosmetics. However, whouldn't we get some performance increase
 if pf(4) didn't bother looking at packets (in certain situations) going
 'out' at all?
 
 I assume that 'pass out all keep state' makes pf(4), at least, do a
 state lookup in the table? AFAIK, that's, in worst case scenario, 16
 searches down the binary tree? That ought to eat a few cycles.

In the immortal words of Donald Knuth:

We should forget about small efficiencies ...
premature optimization is the root of all evil

I really doubt there is a performance issue here, or really, that this
would be the bottleneck. If it is, show the facts, and we (I use the
royal we here, meaning Daniel or Henning) can address it then.

Out.

-kj



Re: pf(4) schemantics

2003-03-20 Thread Kyle R. Hofmann
On Thu, 20 Mar 2003 23:16:10 +0100, Srebrenko Sehic wrote:
 On Thu, Mar 20, 2003 at 02:49:37PM -0700, [EMAIL PROTECTED] wrote:
   Yes, but it could be nice if one could choose, eg.
   set filter-policy {in, out, both} or something.
  
  You can choose. Either type:
  
  block out all
  or
  pass out all keep state
 
 This is cosmetics. However, whouldn't we get some performance increase
 if pf(4) didn't bother looking at packets (in certain situations) going
 'out' at all?
 
 I assume that 'pass out all keep state' makes pf(4), at least, do a
 state lookup in the table? AFAIK, that's, in worst case scenario, 16
 searches down the binary tree? That ought to eat a few cycles.

So far everyone who has responded to you has been polite, despite your
inability to comprehend what they're telling you.  Now, in the proud
tradition of OpenBSD lusers everywhere, I will flame you:

RTFM.
RTFFAQ.
RTFRFC.
RTFS.

 )  (  ((
 (  )  () @@  )  (( (
 (  (  )( @@  (  )) ) (
   ((  ( ()( /---\   (()( (
 ___)  ) )(@ !O O! )@@  ( ) ) )
   )  ) (  ( )( ()@ \ o / (@ ( ()( )
 /--|  |(  o| (  )  ) ((@@(@@ !o! (@)() (
|  \___|  ) ( @)@@)@ /---\-/---\ )@()( )
|  /-+()@@@( // /-\ \\ @@@)@(  .
| |\ =__/|@(@@@ // @ /---\ @ \\ @(@@@(@@@ .  .
|  \   \\=--\|@ O @@@ /-\ @@@ O @@(@@)@@ @   .
|   \   \+--\-)))   @@ !!  %  !! @@)@@@ .. .
|   |\__|_)))/ .@@ !! @@ /---\ @@ !! @@(@@@ @ . .
 \__==   *.@@ /MM  /\O   O/\  MM\ @@@. .
|   |-\   \  (   .  @ !!!  !! \-/ !!  !!! @ .
|   |  \   \  )  . .   !! !!  .(. @.  .. .
|   |   \   \(/   .(  . \)). ( |O  )( O!  . )  .
|   |   /   / ) (  )).  ((  .) !! ((( !! @@ (. ((. .   .
|   |  /   /   ()  ))   ))   .( ( ( ) ). ( !!  )( !! ) ((   ))  ..
|   |_   /   ( ) ( (  ) )   (( )  )).) ((/ |  (  | \(  )) ((. ).
_\\__\__(___)_))_((_())__(_(___.oooO_Oooo.(_(_)_)((_

HAND, HTH.

(ASCII art courtesy of someone else)

(And, more seriously, I suggest that you read the source.  Then it should be
clear why pf works as it does.)

-- 
Kyle R. Hofmann [EMAIL PROTECTED]



Re: pf(4) schemantics

2003-03-20 Thread Andrew Shugg
Kyle R. Hofmann said:
 So far everyone who has responded to you has been polite, despite your
 inability to comprehend what they're telling you.  Now, in the proud
 tradition of OpenBSD lusers everywhere, I will flame you:
 
 
 
  )  (  ((
  (  )  () @@  )  (( (
  (  (  )( @@  (  )) ) (
((  ( ()( /---\   (()( (
  ___)  ) )(@ !O O! )@@  ( ) ) )
)  ) (  ( )( ()@ \ o / (@ ( ()( )
  /--|  |(  o| (  )  ) ((@@(@@ !o! (@)() (
 |  \___|  ) ( @)@@)@ /---\-/---\ )@()( )
 |  /-+()@@@( // /-\ \\ @@@)@(  .
 | |\ =__/|@(@@@ // @ /---\ @ \\ @(@@@(@@@ .  .
 |  \   \\=--\|@ O @@@ /-\ @@@ O @@(@@)@@ @   .
 |   \   \+--\-)))   @@ !!  %  !! @@)@@@ .. .
 |   |\__|_)))/ .@@ !! @@ /---\ @@ !! @@(@@@ @ . .
  \__==   *.@@ /MM  /\O   O/\  MM\ @@@. .
 |   |-\   \  (   .  @ !!!  !! \-/ !!  !!! @ .
 |   |  \   \  )  . .   !! !!  .(. @.  .. .
 |   |   \   \(/   .(  . \)). ( |O  )( O!  . )  .
 |   |   /   / ) (  )).  ((  .) !! ((( !! @@ (. ((. .   .
 |   |  /   /   ()  ))   ))   .( ( ( ) ). ( !!  )( !! ) ((   ))  ..
 |   |_   /   ( ) ( (  ) )   (( )  )).) ((/ |  (  | \(  )) ((. ).
 _\\__\__(___)_))_((_())__(_(___.oooO_Oooo.(_(_)_)((_
 

Mm, toasted marshmallows.

Andrew.

-- 
Andrew Shugg [EMAIL PROTECTED]   http://www.neep.com.au/

Just remember, Mr Fawlty, there's always someone worse off than yourself.
Is there?  Well I'd like to meet him.  I could do with a good laugh.



Re: pf(4) schemantics

2003-03-19 Thread Henning Brauer
On Wed, Mar 19, 2003 at 11:04:26PM +0100, Srebrenko Sehic wrote:
 While working on a pf(4) tutorial/article, I started wondering about the following,
 
 1. What's the reason why packets 'travel' across an interface twice
 (both in and out)? This makes, IMHO, writing very tight rules a bit
 tricky. Especially if you want to start off with 'block all'.

?
they come in on one interface and eventually go out on an interface. might
be the same, might be different, depending on routing table and destination.

 2. Say I 'block all' and then want to pass some traffic from $net_a to
 $net_b. First, I need 2 rules to allow {in,out} traffic from $net_a and
 then 2 rules to allow {in,out} traffic back from $net_b. Sure, you can
 group the {in,out} rules in one, i.e. pass from $net_a to $net_b.
 
 Now, what could be very nice is to pf(4) behave more like the following,
 
 - from pf(4) point of view, there is only inbound traffic from an
   interface. I.e. all traffic originating from $net_a towards other
   networks is always inbound for pf(4).
 - when I write a rule like 'pass from $net_a to $net_b', I don't need
   to write another rule saying 'pass from $net_b to $net_a'. pf(4) takes
   care of that (we are statefull, right?)

eek?

 - say I have 5 interfaces (or 10 VLANs) I filter on. However, not all of
   the networks need to talk to each other. I.e. I could have a $net_c
   that will not talk to $net_a, but will talk to $net_b. It could be
   nice to be able to define this. Otherwise, the traffic never gets
   routed by pf(4).

what? pf never routes traffic until explicitely told to route via route-to.
then what you want in these cases with a shitload of (probably
vlan-)interfaces, is to define the policy on each. wait, ascii art.

  ---
vlan1|  |
vlan2|  |
vlan3|  |-uplink1
vlan4|  |
vlan5|  OpenBSD |
vlan6|  |
vlan7|  |-uplink2
vlan8|  |
vlan9|  |
vlan0|  |
  ---

hmm, suprise, that looks exactly like my setup ;-)
so, let's go on. in vlan01, you have just a webserver. the policy is easy:

pass out on vlan1 proto tcp to $vlan1_webserver port { 80 443 } \
keep state
pass in on vlan1 proto { tcp udp } to $resolvers port 53 \
keep state

that's it, basically. might want to add ssh.

in vlan02, you have just a smtp server, and apply similar rules.
on the external interfaces, let's call them dc0 and dc1, you just do spoof
protection.

int_nets={ vlan1-network vlan2-network .. vlan10-network }
ext_ifs={ dc0 dc1 }
block on $ext_ifs
pass on lo0 quick
block in quick to self
pass in on $ext_ifs to $int_nets keep state
pass out on $ext_ifs from $int_nets keep state

that's it, basically. add some rules to allow some icmp, the box itself to
reach its resolvers etc, and you are done.

with hammering the policy for each vlan on the vlan interface, you have
something very nice achieved. if a box on vlan1 wants to reach a box in
vlan7, it needs to pass the outgoing policy for vlan1 as well as the
incoming one for vlan7.
the only little confusing thing is that all directions are logically
backwards. passing traffic to a webserver _IN_ results in a rule like pass
_OUT_ on vlan1 ... (emphasis added, of course). but that you get used to
quickly.

so, I really don't get what you are proposing.

 People that know a certain commerical firewall will recognize this
 behaviour. Don't get me wrong, I love pf(4), but there might be room for
 improvement.

sure, there always is.

 Comments?

explain better ;-)

-- 
Henning Brauer, BS Web Services, http://bsws.de
[EMAIL PROTECTED] - [EMAIL PROTECTED]
Unix is very simple, but it takes a genius to understand the simplicity.
(Dennis Ritchie)



Re: pf(4) schemantics

2003-03-19 Thread Henning Brauer
On Thu, Mar 20, 2003 at 12:19:13AM +0100, Srebrenko Sehic wrote:
 On Wed, Mar 19, 2003 at 11:27:26PM +0100, Henning Brauer wrote:
   1. What's the reason why packets 'travel' across an interface twice
   (both in and out)? This makes, IMHO, writing very tight rules a bit
   tricky. Especially if you want to start off with 'block all'.
  they come in on one interface and eventually go out on an interface. might
  be the same, might be different, depending on routing table and destination.
 Well, yeah, they do, but why have pf(4) look at them both on in and out
 and on the same interface?

who says same interface here??

   2. Say I 'block all' and then want to pass some traffic from $net_a to
   $net_b. First, I need 2 rules to allow {in,out} traffic from $net_a and
   then 2 rules to allow {in,out} traffic back from $net_b. Sure, you can
   group the {in,out} rules in one, i.e. pass from $net_a to $net_b.
   
   Now, what could be very nice is to pf(4) behave more like the following,
   
   - from pf(4) point of view, there is only inbound traffic from an
 interface. I.e. all traffic originating from $net_a towards other
 networks is always inbound for pf(4).
   - when I write a rule like 'pass from $net_a to $net_b', I don't need
 to write another rule saying 'pass from $net_b to $net_a'. pf(4) takes
 care of that (we are statefull, right?)
  
  eek?
 
 No clear? Let me rephrase. Why not filter on inbound traffic only, even
 though you have 'block all' in your ruleset?

this is like asking why your car engine doesn't work even given you have
fuel in a tank on the seat.
if you want that, you don't do block all, but block in all and let
outgoing traffic pass unconditionally. easy, eh?

 The commerical firewall I was talking about previously is Cisco PIX.

The first PIX was cool: you could install OpenBSD on it without trouble ;-)

 net_a -- pf(4) --- net_b, and _not_
 
 net_a - pf(4) --- net_b

yeah, and IPF behaved the same, and this behaviour is stopid. makes the
setup I drawed below impossible. you can have the same with pf by passing
outbond unconditionally.

   - say I have 5 interfaces (or 10 VLANs) I filter on. However, not all of
 the networks need to talk to each other. I.e. I could have a $net_c
 that will not talk to $net_a, but will talk to $net_b. It could be
 nice to be able to define this. Otherwise, the traffic never gets
 routed by pf(4).
  
  what? pf never routes traffic until explicitely told to route via route-to.
  then what you want in these cases with a shitload of (probably
  vlan-)interfaces, is to define the policy on each. wait, ascii art.
 
 Of course, kernel does, pf(4) only looks at the traffic. However, it
 might be useful is certain situations. Like, 10 VLAN's, but I only want
 to filter on 5. With a rule 'block all', all 10 VLAN traffic would be
 blocked, right?

so block only on those interfaces you wanna filter on? like, this is
obvious, hmm?

 To rephrase, it could be nice if I could define which interfaces pf(4)
 should care about. Something like,
 
 set filter interface {vlan01, vlan02, vlan03}

indeed I have something like this in mind, but purely for performance
reasons. might add that after 3.3. perhaps not. we'll see.

 and assuming you have 'block all'. Right?

no, read on.

and HELL, you say all the time you do not want block all, so why are you
doing block all in your ruleset???

 Well, you managed to confuse me now. Let's throw in some simplified
 ascii and sample rules,
 
 $ext_if - pf(4)  $int_if
 
 ext_if = fxp0
 int_if = fxp1
 ext_net = 192.168.0.0/24
 int_net = 192.168.1.0/24
 webserver = 192.168.1.2/32
 
 block in all
 block out all
 
 ## allow traffic on $ext_if to $webserver on 80/tcp and 443/tcp
 pass in on $ext_if proto tcp from any to $webserver port {80, 443} \
   keep state
 
 This would not work. Why? We need to pass out on $ext_if as well (since
 pf(4) filters on both directions). Not only that, we need to pass in/out
 on $int_if as well, since 'block in/out all' applies to all interfaces.

ARRRGGG!

s/block out all// and you are done! you obviously do not want to block
outgoing, so why do you tell pf to do so? why?

 What could be nice is to have this kind of rule working. pf(4) could
 allow traffic back from $webserver, even though I have 'block in/out
 all'. This is how PIX works.

and this is how ipf worked, and it was majorly stupid, because the setuop I
described is no more possible then, while you just pass outgoing
unconditionally and HAVE what you are asking already, and that since the
first pf incarnation in OpenBSD 3.0.

 Am I being a bit more clear now? Or am I _totally_ misunderstanding
 pf(4) innerworkings? ;)

you are just thinking very wrong. you are telling pf to block traffic which
goes OUT on an interface, and complain that pf blocks traffic which is
outgoing on one interface. but you told pf to! so don't tell it to, pass
poutgoing unconditionally, case 

Re: pf(4) schemantics

2003-03-19 Thread Trevor Talbot
On Wednesday, Mar 19, 2003, at 15:19 US/Pacific, Srebrenko Sehic wrote:

block in all
block out all
## allow traffic on $ext_if to $webserver on 80/tcp and 443/tcp
pass in on $ext_if proto tcp from any to $webserver port {80, 443} \
keep state
This would not work. Why? We need to pass out on $ext_if as well (since
pf(4) filters on both directions).
In this specific case, the keep state option will allow traffic back
out on $ext_if, from $webserver, provided it is related to the original
tcp port {80, 443} traffic that triggered it.  You do not need any other
pass out on $ext_if rules for $webserver for this purpose.
Are you unsure what stateful behavior is?