I just found out about this list, and realized this email was more
appropriate to send here.

In a prior email, I pointed out another case of asymmetry; namely,
that rdr works on the dst IP of inbound packets, and nat works on the
src of outbound packets, but there doesn't appear to be a way to
change the src of inbound packets or the dst of outbound packets (save
for those made in the return direction of a state entry made by one of
the above transformations).


---------- Forwarded message ----------
From: Travis H. <[EMAIL PROTECTED]>
Date: Oct 8, 2005 2:58 AM
Subject: why is pass/block necessary to tag or queue?
To: [EMAIL PROTECTED]


It'd be nice if you didn't have to alter a packet's pass/block status
when tagging for policy-based filtering or queuing.  Although it
doesn't make much sense to do anything to a packet that you're
planning on blocking, decoupling these activities makes a certain
degree of sense.

For example, you may have a "default block" rule up top, then you
assign to queues, then you do some explicit allows.  However, you
can't (to my knowledge) assign to a queue without altering the default
block rule you had up top.  You *can* solve this by re-ordering, and
putting your queueing before the default block, but then it's not
nearly as clear what your default behavior is.

Here's a contrived example using a "enqueue" rule I made up for
reasons that shall become clear.  Note that enqueue implies an outward
directionality, as you can't queue inbound packets.

# define the queues
altq blah blah..
queue high_priority blah blah...

# Default deny - comes first so everyone knows we mean business.
block all

# Assign to queues (without doing filtering)
# All UDP port 53 (rule A) and TCP port 53, 80, 119 (rule B) traffic
is high priority
enqueue high_priority on $wan_if proto udp from any to any port 53
enqueue high_priority on $wan_if proto tcp from any to any port { 53, 80, 119 }
# All traffic from specialclient is high priority (rule C)
enqueue high_priority on $wan_if from specialclient to any

# Allow only certain traffic out
# rule X - I only let the average host do UDP to port 53 and 111 (DNS and RPC)
pass out quick on $wan_if proto udp from any to any port { 53, 111 } keep state
# rule Y - I only let the average host do TCP to port 53 and port 80
(DNS and HTTP)
pass out quick on $wan_if proto tcp from any to any port { 53, 80 } keep state
# rule Z - I let anyone speak anything to myserver
pass out quick on $wan_if from any to myserver keep state

Put another way, sequential rules can be thought of as disjunctive normal form:

classify high priority if (A or B or C)
pass if (X or Y or Z)

Unfortunately the two are coupled, so that I must write a
pass+classify rule that operates on the conjunction (intersection):

pass and classify high priority if ((A or B or C) and (X or Y or Z))
pass and don't classify if (X or Y or Z)

Technically the last rule could also be written thusly:
pass and don't classify if ((X or Y or Z) and NOT (A or B or C))

However, that's unnecessary, since a priority assignment in the first
group of pass rules "sticks", even though the second group of pass
rules matches.

If we wished all non-high-priority traffic to be assigned to another
(non-default) queue, we'd need to do something along those lines, and
apply DeMorgan's law.

But since a series of pass rules is a disjunction, and a single rule
is essentially a conjunction of conditions, we must convert the
intersection to disjunctive normal form using the boolean distributive
law:

pass and classify high priority if ((A and X) or (A and Y) or (A and
Z) or (B and X) or (B and Y) or (B and Z) or (C and X) or (C and Y) or
(C and Z))
pass and don't classify if (X or Y or X)

This shows us that six rules can convert to as many as twelve rules,
assuming that A, B and C are conditions on different fields in the
packet, and X, Y and Z are on different fields of the packet.  If X
and Y were both conditions on the source IP, for example, we could
represent (X or Y) as one condition in a single rule and simplify to:

pass and classify high priority if ((A and (X or Y) or (A and Z) or (B
and (X or Y)) or (B and Z) or (C and (X or Y)) or (C and Z))
pass and don't classify if (X or Y or X)

This still leaves us with 9 rules.

You don't have to decide on a pass/block  when you decide to NAT on an
interface, or when you decide to RDR an incoming packet.  By symmetry
why should you have to decide on pass/block when tagging or queuing?

My modest proposal is the addition of two new rules, "enqueue" and
"tag".  I could easily add these to pfctl's parser (I am so glad it
uses yacc and not a hand-written recursive descent parser), but I am
not sure if changes would be required to the engine in the kernel.
Also, if there are any problems with this proposal I'd like to find
out before I've done a lot of patching. ;-)
--
http://www.lightconsulting.com/~travis/  -><-
GPG fingerprint: 50A1 15C5 A9DE 23B9 ED98 C93E 38E9 204A 94C2 641B

Reply via email to