On Fri, Nov 01, 2002 at 02:14:58AM +1000, loki wrote:

> rather than having an "embryo" flag on a rule tho, id make it its own
> directive and have it before the normal filter rules, therefore evaluated
> before the normal rules. state is checked before rules. since embryo
> states are almost states, it makes sense to me that they get checked
> before the rules as well.

I don't think adding such a mechanism to the rule set improves
performance, quite the opposite. A single pointer comparison (for an
empty tree of embryonic states) is about as cheap as it gets. Look at
what already happens for each packet going through the packet filter, an
additional single comparison is just a tiny fraction. If we'd argue
about half a dozen cpu instructions, we could gain a lot more by
removing a single byte/packet counter. What does pfctl -si show for
'Counters, match'? 1000 rule set evaluations per second? That would mean
1000 additional pointer comparisons per second. Now benchmark how many
such comparisons you can do per second without increasing cpu load by
more than 1%, on a 486/133 if you like :)

The point of an embryonic state inserted by a proxy is that it's an
exception from the static filter policy. If you could allow these
connections using a static rule set, there would be no need for
embryonic states. If you can't, you also have troubles expressing,
statically, _what_ embryonic states to allow. A proxy making use of such
a feature would require access to /dev/pf and it would have to be written
as carefully as authpf, for instance.

> having such a rule (or rules) has several other advantages, you could
> create several trees, one for each proxy that requires it (include a
> mechanism for the proxy to talk to its own tree). you could specify which
> field of the state entry is variable (id still say that remote src port
> would be th only one, but its nice to be flexible). you could specify tcp
> flags and state modulation. whatever is needed for connections created by
> the proxy.

I can't think of a case where anything but the source port is missing,
actually. And of course an embryonic state could hold any information a
normal state can (like address translations, timeout values, etc.) or any
information otherwise read from the rule that creates an ordinary state
(like modulation, route-to, etc.)

The proxy wouldn't need to do anything but insert an embryonic state (no
enumeration, reading or changing of tree nodes), specifying a timeout
value after which it's removed if not completed. The whole kernel part
shouldn't get larger than a couple of lines, and the only change
relevant for userland would be an additional ioctl.

There's another way of comparing performance: if you're using embryonic
states with a proxy, you're dealing with connections you want to allow.
You want the firewall to create state and pass the packets of that
connection. Creating a state entry from an embryonic state after doing a
normal state lookup (failing) and a lookup in the embryonic state table
is generally cheaper than walking the rule set and creating state in
that way (assuming you could express a pass keep state rule there for
such connections). If your embyonic state table constantly contains
several thousand entries, the lookup for each new connection will of
course have an impact. The question, in such a setup, is how many times
an embryonic state matches and becomes a normal state, saving a rule set
evaluation (which would always follow a failed state table lookup). I
guess it boils down to the ratio of expected proxy connections vs. newly
created normal states (or blocked connections) per second.

Daniel

Reply via email to