Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Apr 1998 14:55:53 +0200
From:      Eivind Eklund <eivind@yes.no>
To:        hackers@FreeBSD.ORG
Subject:   Re: changing ipfw interface (was Re: cvs commit: src/sys/netinet ip_fw.c)
Message-ID:  <19980423145553.50690@follo.net>
In-Reply-To: <9804231048.AA01717@avalon.reed.wattle.id.au.>; from darrenr@reed.wattle.id.au on Thu, Apr 23, 1998 at 08:44:05PM %2B1000
References:  <19980423015125.15103@follo.net> <9804231048.AA01717@avalon.reed.wattle.id.au.> <19980423135332.35381@follo.net>

next in thread | previous in thread | raw e-mail | index | archive | help
This was supposed to go here, not in private to Darren :-( (I'll try
to get his permission to forward his reply).

On Thu, Apr 23, 1998 at 08:44:05PM +1000, darrenr@reed.wattle.id.au wrote:
> In some email I received from Eivind Eklund, sie wrote:
> > 
> > On Thu, Apr 23, 1998 at 01:50:05AM +1000, darrenr@reed.wattle.id.au wrote:
> > > In some email I received from Eivind Eklund, sie wrote:
> > > > 
> > > > That's what I'm saying - it blow the userland interface.  It means
> > > > that anything using IPFW has to track the kernel version exactly.
> > > 
> > > There are numerous programs like this already - ps, netstat, top, etc.
> > > 
> > > I'd say "deal with it".
> > 
> > ps et.al.  aren't that critical.  Sure, it suck that they are that
> > way, but if ps is broken, _you can still get to the machine_.  This is
> > not the case with IPFW.  Having a structure-dependent interface for
> > the firewall is IMO not acceptable.
> 
> Then maybe ipfw is `being handled wrongly'.  You have code which lives in
> the kernel that must interface with the userland *tightly*.  That entire
> bundle must stay consistant with respect to versions.  It's not so much
> dependant on the kernel version, but rather you're changing the "ipfw"
> version when you change the kernel or user code.

I don't care what I'm changing.  I don't have a problem keeping my own
machines working (though I must admit I feel slightly scared when I do
remote updates that change IPFW).  My problem is that I see _users_
being screwed by this each time we change IPFW.

> For what it's worth, using ipfw as an LKM (which isn't compiled out of
> /sys) maybe what you're really thinking of here although then your kernel
> security drops.  Actually, I'm not sure what you're proposing makes any
> difference unless you're planning on using BPF to write ipfw rules, as
> the interface becomes `programmable' (along with the bloat required in
> the kernel to support it unless that's not a factor in your requirements).

I've included (below) the original mail I sent to hackers on the
subject.  This interface allow anything that would 'just have required
a re-compile of the old sources' to work.

Anything else means we also have an unstable programmatic interface;
that's _bad_, unless we're going to say that only /sbin/ipfw is going
to be allowed to use that interface.

Eivind.

--------------------
Message-ID: <19980131071101.11786@follo.net>
Date: Sat, 31 Jan 1998 07:11:01 +0100
From: Eivind Eklund <eivind@yes.no>
To: hackers@FreeBSD.ORG
Subject: On a new IPFW interface, w/potentially wider applications
Lines: 196

Does the below (inspired by tags on the Amiga) sound like a good idea
for IPFW?

Does it sound like it is such a good idea that it should be extended
to a generic method of manipulating kernel objects instead of doing it
only for IPFW?  (Cost: At least one syscall number, up to four if we
want separate syscalls for add/delete/commit/cancel, as well as making
it approx twice as much work to implement as a special case for IPFW).

And speaking of kernel interfaces: I've been thinking of a way of
implementing capabilites (in the security sense) which would share a
lot of properties with this interface, and might be cheap to implement
along with it (I'd have to look more closely at the design issues to
be certain).  Do anybody but me feel that this (capabilites) would be
a good direction to go for FreeBSD, or do people think we'll become
'too weird' that way?


[Originally in a mail to Alex Nash]
Speaking of the IPFW interface: I am quite tired of seeing necessary
changes to that break other software.  What do you say about an
interface like the below?  If that's OK, I'll look into implementing
it or getting my mentoree to do it (unless you have enough time and
want to do it yourself to get it done quickly :-)

The basic idea behind the below is the make the interface create rules
by itself with default values first, and then change the created rule
by a set of setsockopt() calls until its parameters is correct.  The
new rule is then added to the list by a commit operation.
Implementation detail: The interface should limit the number of
non-committed rules to a fixed number, to stop kernel resource
starvation by a userland process.  Old non-committed rules should
probably be thrown away in preference to new ones being denied; that
will more easily protect against programming errors.

I think a new new userland library for easy access to this would be a
good idea; see bottom for details on how I envision this.

------------------------------------------------------------------

    New socket options:
IP_FW_START_ADD:
    struct {
       long version;            /* Interface version, below is version 0 */
       unsigned long list;      /* Which rule list to work with (0 is
                                   the only presently correct list
                                   number) */
       int number;              /* "Line number"/rule number for IPFW */

       unsigned long coookie;   /* Filled in by the kernel; used as a
                                   capability (in the security sense)
                                   to identify this add operation for
                                   later manipulation. */
    }

This socket option starts a new add request; the add request will be
filled with data and committed to the firewall lists later.  List is
allowed to be able to have more than one firewall list later, to allow
filtering the way Cisco implements it.  (If the structure is not
copied to the kernel for a getsockopt() operation, we'll just have to
make do with just returning a cookie.  The above implementation would
be preferable, as we won't have to specify as many parameters for to
IP_FW_SET, and can upgrade the interface at will).


IP_FW_SET:
    struct {
       unsigned long cookie;    /* Previously returned from
                                   IP_FW_START_ADD.  This identify
                                   which non-completed rule to
                                   manipulate.  */
       unsigned long field;     /* Which field of the rule to
                                   manipulate */

       unsigned char data[92];  /* The data for this field. 92 will
                                   allow it to fit in a 108 byte
                                   socket option together with a
                                   64-bit cookie and 'field' ;-) */
    }
Manipulate the field of an as-of-yet uncommitted rule.

IP_FW_COMMIT:
    struct {
       unsigned long cookie;    /* The capability of the rule to
                                   commit */
    }
Commit a new rule into the kernel.


IP_FW_CANCEL:
    struct {
       unsigned long cookie;    /* The capability of the rule to
                                   cancel */
    }
Drop a rule that has been built in the kernel.


IP_FW_START_GET:
    struct {
       long version;            /* Version of interface to use
                                   (presently 0) */
       unsigned long list;      /* Which list of rules to get
                                   (presently 0) */
       unsigned long cookie;    /* Capability; filled in by the
                                   kernel. */
    }
Get a capability for getting a list of firewall rules from the kernel.

IP_FW_GET_VALUE:
    struct ip_fw_get_value_struct {
       unsigned long cookie;    /* Capability for getting data */
       unsigned long field;     /* Which field to get */
       unsigned char data[92];  /* Data gotten from the kernel */
    }
Get the data for a field from the kernel.  If we can't pass this
structure to the kernel, we're in mucho, mucho trouble, and probably
will need to connect the state of reading a list to a particular
socket, which would be a pity.  The size of the data read from the
kernel is found by subtracting offsetof(struct
ip_fw_get_value_struct,data) from the amount of data the kernel says
it has written.

IP_FW_GET_NEXT:
    struct {
       unsigned long cookie;    /* Capability for reading operation in
                                   the kernel we're presently
                                   manipulating. */
    }
Proceed to next rule along a rule-list we're reading.


IP_FW_GET_DONE:
    struct {
       unsigned long cookie;    /* Capability for reading operation in
                                   the kernel we're presently
                                   manipulating. */
    }
Finish with the capability for a particular read operation.

-------------------------------------------

Now, to make the userland side of this easy, I would like an access
library:

int
ipfw_addrule(
unsigned long list_number,
unsigned long rule_number,
...);

where ... is filled with option/value pairs, like in
   (long)IPFW_SRCADDR, &inaddr,
   (long)IPFW_PORT, 6667,
   (long)0                      /* Termination */

For deletion,
int
ipfw_delrule(
unsigned long list_number,
unsigned long rule_number
);

For getting lists:
{
    unsigned long cookie;
    struct ip_fw rule;

    cookie = ipfw_getlist_start(0); /* List number */
    if (!cookie)
       return;

    while (ipfw_getlist_entry(cookie,
       IPFW_SRCADDR, &rule.fw_src,
       IPFW_DSTADDR, &rule.fw_dst,
       IPFW_SRCMASK, &rule.fw_smsk,
       IPFW_DSTMASK, &rule.fw_dmsk,
       (long)0)) {
       ... do stuff ...
    }
    ipfw_getlist_done(cookie);
}

The data don't have to go into the old ip_fw struct, of course -
that's just as an example.



Well, what do you think?  It covers our present needs, and as far as I
can see our future needs - if we need single fields of more than 92
bytes we can always set them as several operations or change the
interface by changing the version.  It allow us to add entries to the
data structures without killing old apps.  It should be fairly easy to
implement, and fairly easy for programmers to use, especially if we
add the library.

Eivind.


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



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