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 Message-ID: <19980131071101.11786@follo.net>
next in thread | raw e-mail | index | archive | help
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.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19980131071101.11786>