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