Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Nov 1999 01:33:04 -0500 (EST)
From:      Brian Fundakowski Feldman <green@FreeBSD.org>
To:        ipfw@FreeBSD.org
Cc:        arch@FreeBSD.org
Subject:   new IPFW
Message-ID:  <Pine.BSF.4.10.9911240047480.40905-100000@green.dyndns.org>

next in thread | raw e-mail | index | archive | help
I've finally sat myself down to take the first step in getting the new
IPFW done.  I'll start by listing some of the different ideas I've had,
CC'd to arch@ so that I pick up the audience of people I need.
   First of all, what was done right about the old IPFW?  The basic
architecture is nice; a chain of rules is quite efficient, but can
be improved upon with basic optimization techniques, which should
be done.  The syntax is pretty nice, and IPFW is really very fast.
It is called by a hook so was easy to become a KLD.
   Now, the new IPFW could directly replace the old IPFW given that
1) it uses the same entry point, and 2) uses the same API.  The API
for calling IPFW per-packet itself is not bad.
   There are many things to improve upon.  The old IPFW is very static
and limited in certain regards.  It uses a monolithic "rule" struct
to store everything related to that rule, which is obviously not
the right thing to do.  There are arbitrary limits on rules because
of this, and it makes the API pretty sickening.
   So what can be done better than the old IPFW?  First of all, it
should be easy to retrieve a rule and change it.  I should be able
get, for instance, rule 1000 (in old IPFW format, of course)
	1000 deny all from 127.0.0.0/24 to any
and replace it with
	1000 deny all from 127.0.0.0/8 to any.  This would require
a retrieval, deletion, and addition under the current IPFW user API.
Instead, there should be an API call that woul effectively say
"change rule 1000's destination address netmask to /8".
   I also want to be able to make things nicer to do.  One, a certain
amount of state should be able to be stored, allowing stateful
operations in IPFW where previously there were none.  Commands should
be more dynamic;  all the old rule actions should be supported
(pass, deny, fwd, divert, pipe, et al), whereas new ones should be
easy to add by PIM (Pluggable IPFW Modules? =).  Perhaps it would
be nice to have a real "branch" action instead of using more hackish
gotos, which can be terminated with deny all from any to any (which
should be a synonym for "end"; you should be able to write procedures
in IPFW).
   All actions except for deny should have a "continue" option, where
the packet matching would both match that rule and follow its action,
but also pass on to the next rule.  This would obsolete the never-working-
anyway "tee" action, and make things much easier, if thought about
properly.  To cut down on number of rules (that basically go pass such-and-
such, deny other-such) with redundant information, which would of course
take up less memory and processor time, each "match" type could be negated,
such as, with a default-to-pass rule set, "deny [implicit all] ( src [alt:from]
127.0.0.0/8 or dest [alt:to] 127.0.0.8 ) and not interface lo0".  This would
allow actual logic in rules, albeit with slightly more complexity in
the IPFW implementation in the kernel.  This would be a huge gain for
the administrator of the firewall, in that {,s}he could use a more
natural programming syntax, rather than the current, simplistic,
absolutely non-programmable (but klugeable) IPFW.  For the matching rules
themselves, they should be dynamic and possibly object-oriented.
   I envision something like this:
struct ipfw_rule {
	int rule_number; /* maybe name alias, too? :) */
	u_int32_t rule_options; /* for what doesn't fit in the action */
	rule_action *action;	/* action is an object and contains ancillary data */
	SLIST_HEAD(, match_type) matches; /* must match all of these in the null-terminated list to match the rule */
	struct irstats {
		u_int64_t matches;
		etc...
	} stats;
};

The match_type could consist of something like:
	SLIST_FOREACH(matchrule, rule->matches, rule_list_entry) {
		if (!matchrule->dispatch(matchrule, packet, other info))
			return 0;
	}
	passed all matches.
	action....

Where matcher_dispatch would read the match object, which would be inherited
from the base type:

struct base_matchrule {
	match_func_t *dispatch;
};

and other types would be something like {

struct address_matchrule {
	match_func_t *dispatch;
	u_int32_t flags; /* source/dest, IS or NOT, etc. */
	struct sockaddr_maxsize addr; /* support in and in6 */
};
And this would be the object-oriented architecture part.

I'm going to wrap this up since I'm up quite late (well, only 1:30, but
I'm still a growing person...), and I don't want to start to get too
incoherent.  Thank you for your time and attention with my IPFW ideas,
and please send comments and ideas to me;  heck, I'd love to start
a long discussion about this, so we can flesh everything out :)

-- 
 Brian Fundakowski Feldman           \  FreeBSD: The Power to Serve!  /
 green@FreeBSD.org                    `------------------------------'



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ipfw" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.10.9911240047480.40905-100000>