In some email I received from Chris G Demetriou, they wrote:
[...]
> > I guess if you wanted, you could allow for two "programs" to be resident
> > in memory (for BPF) for both input and output, on each interface (total
> > of 8 for a dual interface "firewall" host) and switch between the two.
> > (I assume this is what you are getting at above). So long as it was
> > possible to support this, it'd alleviate the problem.
>
> Actually, the fact that you need that many filters indicates to me
> that the job of writing the "master filter" would be a bit tougher...
> but i think it could still be done with a few (minimal) modifications
> to BPF. (basically, also pass "interface pointer" and "in/out" up to
> BPF, etc.)
With recent discussion about compatibility of executeables between NetBSD
and FreeBSD, I'm wary of changes to such a common "base", which is also
supported elsewhere. I guess some of you in core aren't so worried about
this, perhaps, but I can't see why anyone would like it.
I was thinking about it a bit more, and was thinking maybe it'd work better
if each filter rule was separately compiled and a list of compiled rules
executed. In writing a packet filter for firewalling, I've found that it
is useful to have "fall through" rules, as well as match-and-stop.
Converting a simple filter list to a working BPF "program" to do that I
suspect would be difficult. Maybe it'd work to even have a two stage
parser operate, which stripped out the "firewall" directives, and left
the "host foo and port bar" to go through a compiler and then into BPF.
Below is an extract from a current set of packet filter rules I use to
implement a firewall:
log in on le0 from any to any with ipopts
block in log on le0 from any to any with short frag
log in on le0 proto tcp from any to any port != 80 flags S
block in log quick on le0 from 127.0.0.0/8 to any
block in log quick on le0 from 128.250.132.0/24 to any
pass in quick on le0 from any to 128.250.133.13/32
pass in quick on le0 from 128.250.133.13/32 to any
block in quick on le0 from any to any with ipopts
pass in on le0 from any to any
block in on le0 proto udp from any to 128.250.132.0/24
block in on le0 proto tcp from any to 128.250.132.0/24 flags S
block in on le0 proto icmp from any to 128.250.132.0/24
(quick = match and stop) - How easy would it be to write a BPF set of
rules to do the same ? The others are fall through and use the keyword
at the start if it matches.
Now, it's pretty easy for me to add a new keyword to that simple
language and not worry too much about what effect it will have on some
other part.
I might also add, that it is possible, from the filters produced through
what I've written, with not much effort to extract the filters from the
kernel and present them back in a form which looks exactly the same as
what you see above. If you start using BPF (and decide to optimize your
ruleset when you compile), then there is no guarantee of being able to
redisplay it the same as it was before. This isn't for debugging
purposes (being able to view current filters), but more of a requirement
of being able to view what is current upon demand.
Also, the above filtering takes into account that the packet is already
an IP packet. BPF code is usually produced for dealing with the entire
packet present. Whilst it would be possible to write BPF code which still
worked without having this header present, it would require its own
"compiled", separate from that usually used by programs working with
/dev/bpf* (maybe that's just another hack to what already exists).
Ideally, there would be two filter lists per interface (struct ifnet) for
inbound and outbound, rather than have "master lists" for in/out. I got
8 from thinking maybe you'd need another to store a "swap-to" list, but
you could get away with one of those. I've tried to have minimal effect
on the system when implementing my filter and have not done this. This
is to hopefully make it easier to incorporate the basic idea/structure
into any Un*x.
darren