* [PATCH 1/2] ipt_MARK extension with backwards compatibility (kernel side).
@ 2004-11-25 4:49 Rusty Russell
2004-11-26 22:58 ` Pablo Neira
0 siblings, 1 reply; 8+ messages in thread
From: Rusty Russell @ 2004-11-25 4:49 UTC (permalink / raw)
To: Netfilter development mailing list; +Cc: Anders Fugmann, Bart De Schuymer
We've been chasing this for a while; thanks to Bart for the final piece!
How to extend an extension:
1) If you already have a flags word in your structure which is checked
by existing versions of the code, you can simply add new flags: this
will fail on old kernels and work on new kernels.
2) If not, you must extend the size of the structure, so old kernels
will fail, and new kernels will be able to tell whether they are to use
the new or old structure. The IPT_ALIGN'ed size of the structure must
change for this to work!
3) In your userspace extension, use the *flags arg to note if you need
the new structure. and in your final_check() function, reduce the
targetsize or matchsize to the old structure size if you didn't use the
new features.
4) Inside the kernel, create a dummy "struct ipt_target" or "struct
ipt_match" for the backwards compatibility mode. This must have the
same name as the real one, but must not be registered. In your
checkentry() routine, set t->u.kernel.target or m->u.kernel.match to the
old version if the old size is used.
5) See ipt_MARK for an example.
Name: Add bitops to ipt_MARK without breaking compatibility
Status: Tested under nfsim
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Anders Fugmann <afu@fugmann.dhs.org> wrote a patch to add bitops to
ipt_MARK. I made a version which doesn't rely on any infrastructure
changes and is still backwards compatible (it'd be neater with
interface changes, but <shrug>).
Bart De Schuymer <bdschuym@pandora.be> provided the idea of overriding
the target type.
Index: linux-2.6.10-rc2-bk8-Netfilter/include/linux/netfilter_ipv4/ipt_MARK.h
===================================================================
--- linux-2.6.10-rc2-bk8-Netfilter.orig/include/linux/netfilter_ipv4/ipt_MARK.h 2000-03-18 05:56:20.000000000 +1100
+++ linux-2.6.10-rc2-bk8-Netfilter/include/linux/netfilter_ipv4/ipt_MARK.h 2004-11-25 13:29:47.000000000 +1100
@@ -1,8 +1,18 @@
#ifndef _IPT_MARK_H_target
#define _IPT_MARK_H_target
-struct ipt_mark_target_info {
+struct ipt_mark_target_old_info {
unsigned long mark;
};
+enum {
+ IPT_MARK_SET=0,
+ IPT_MARK_AND,
+ IPT_MARK_OR
+};
+
+struct ipt_mark_target_info {
+ unsigned long mark;
+ u_int8_t mode;
+};
#endif /*_IPT_MARK_H_target*/
Index: linux-2.6.10-rc2-bk8-Netfilter/net/ipv4/netfilter/ipt_MARK.c
===================================================================
--- linux-2.6.10-rc2-bk8-Netfilter.orig/net/ipv4/netfilter/ipt_MARK.c 2004-02-18 23:54:37.000000000 +1100
+++ linux-2.6.10-rc2-bk8-Netfilter/net/ipv4/netfilter/ipt_MARK.c 2004-11-25 13:33:40.000000000 +1100
@@ -20,7 +20,7 @@
MODULE_DESCRIPTION("iptables MARK modification module");
static unsigned int
-target(struct sk_buff **pskb,
+old_target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
@@ -36,6 +36,45 @@
return IPT_CONTINUE;
}
+static unsigned int
+target(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const void *targinfo,
+ void *userinfo)
+{
+ const struct ipt_mark_target_info *markinfo = targinfo;
+ int mark = 0;
+
+ switch (markinfo->mode) {
+ case IPT_MARK_SET:
+ mark = markinfo->mark;
+ break;
+
+ case IPT_MARK_AND:
+ mark = (*pskb)->nfmark & markinfo->mark;
+ break;
+
+ case IPT_MARK_OR:
+ mark = (*pskb)->nfmark | markinfo->mark;
+ break;
+ }
+
+ if((*pskb)->nfmark != mark) {
+ (*pskb)->nfmark = mark;
+ (*pskb)->nfcache |= NFC_ALTERED;
+ }
+ return IPT_CONTINUE;
+}
+
+
+static struct ipt_target ipt_mark_old_reg = {
+ .name = "MARK",
+ .target = old_target,
+ .me = THIS_MODULE,
+};
+
static int
checkentry(const char *tablename,
const struct ipt_entry *e,
@@ -43,6 +82,20 @@
unsigned int targinfosize,
unsigned int hook_mask)
{
+ const struct ipt_mark_target_info *markinfo = targinfo;
+ struct ipt_entry_target *t
+ = container_of(targinfo, struct ipt_entry_target, data);
+
+ if (strcmp(tablename, "mangle") != 0) {
+ printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+ return 0;
+ }
+
+ if (targinfosize==IPT_ALIGN(sizeof(struct ipt_mark_target_old_info))) {
+ t->u.kernel.target = &ipt_mark_old_reg;
+ return 1;
+ }
+
if (targinfosize != IPT_ALIGN(sizeof(struct ipt_mark_target_info))) {
printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
targinfosize,
@@ -50,8 +104,11 @@
return 0;
}
- if (strcmp(tablename, "mangle") != 0) {
- printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+ if (markinfo->mode != IPT_MARK_SET
+ && markinfo->mode != IPT_MARK_AND
+ && markinfo->mode != IPT_MARK_OR) {
+ printk(KERN_WARNING "MARK: unknown mode %u\n",
+ markinfo->mode);
return 0;
}
--
A bad analogy is like a leaky screwdriver -- Richard Braakman
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 1/2] ipt_MARK extension with backwards compatibility (kernel side). 2004-11-25 4:49 [PATCH 1/2] ipt_MARK extension with backwards compatibility (kernel side) Rusty Russell @ 2004-11-26 22:58 ` Pablo Neira 2004-11-27 10:45 ` New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) Sven Anders 2004-12-07 21:20 ` [PATCH 1/2] ipt_MARK extension with backwards compatibility (kernel side) Pablo Neira 0 siblings, 2 replies; 8+ messages in thread From: Pablo Neira @ 2004-11-26 22:58 UTC (permalink / raw) To: Rusty Russell Cc: Anders Fugmann, Netfilter development mailing list, Bart De Schuymer [-- Attachment #1: Type: text/plain, Size: 1359 bytes --] Rusty Russell wrote: >We've been chasing this for a while; thanks to Bart for the final piece! > > that is good news, we finally drop that heavy anchor :) >2) If not, you must extend the size of the structure, so old kernels >will fail, and new kernels will be able to tell whether they are to use >the new or old structure. The IPT_ALIGN'ed size of the structure must >change for this to work! > > My idea, I don't know how crazy it is. Instead of using the size to guess the target/match version, we could steal 1 byte from char name[] to define a new field called version, so we could register different versions of a match/target. Possible scenarios: a) Old kernel, new iptables binary: since names are manipulated with str* functions, it shouldn't be any problem with the version stuff because it will be ignored since info after first '\0' is ignored. b) New kernel, old iptables: version value is zero, so kernel guess that it must handle the thing with first version of the target/match. Possible Inconvenients?: a) Current target/match with a name 29 byte long. Hm I think that there's no target/match like that. b) Could gcc mess things with alignments and break compatibility? c) Something I'm missing 8) Attached just the beginning of a possible patch, things like ipt_register_* version aware should be implemented. -- Pablo [-- Attachment #2: patch --] [-- Type: text/plain, Size: 3120 bytes --] ===== include/linux/netfilter_ipv4/ip_tables.h 1.12 vs edited ===== --- 1.12/include/linux/netfilter_ipv4/ip_tables.h 2004-11-02 01:39:53 +01:00 +++ edited/include/linux/netfilter_ipv4/ip_tables.h 2004-11-26 22:33:07 +01:00 @@ -25,6 +25,7 @@ #include <linux/compiler.h> #include <linux/netfilter_ipv4.h> +#define IPT_TARGET_MATCH_MAXNAMELEN 29 #define IPT_FUNCTION_MAXNAMELEN 30 #define IPT_TABLE_MAXNAMELEN 32 @@ -53,7 +54,9 @@ u_int16_t match_size; /* Used by userspace */ - char name[IPT_FUNCTION_MAXNAMELEN]; + char name[IPT_TARGET_MATCH_MAXNAMELEN]; + /* Version */ + u_int8_t version; } user; struct { u_int16_t match_size; @@ -76,7 +79,9 @@ u_int16_t target_size; /* Used by userspace */ - char name[IPT_FUNCTION_MAXNAMELEN]; + char name[IPT_TARGET_MATCH_MAXNAMELEN]; + /* Version */ + u_int8_t version; } user; struct { u_int16_t target_size; @@ -344,7 +349,10 @@ { struct list_head list; - const char name[IPT_FUNCTION_MAXNAMELEN]; + const char name[IPT_TARGET_MATCH_MAXNAMELEN]; + + /* Version */ + u_int8_t version; /* Return true or false: return FALSE and set *hotdrop = 1 to force immediate packet drop. */ @@ -378,7 +386,10 @@ { struct list_head list; - const char name[IPT_FUNCTION_MAXNAMELEN]; + const char name[IPT_TARGET_MATCH_MAXNAMELEN]; + + /* Version */ + u_int8_t version; /* Called when user tries to insert an entry of this type: hook_mask is a bitmask of hooks from which it can be ===== include/linux/netfilter_ipv4/listhelp.h 1.4 vs edited ===== --- 1.4/include/linux/netfilter_ipv4/listhelp.h 2004-02-20 23:51:48 +01:00 +++ edited/include/linux/netfilter_ipv4/listhelp.h 2004-11-26 23:08:52 +01:00 @@ -118,6 +118,24 @@ return 1; } +/* Returns false if same name already in list, otherwise does insert. */ +static inline int +list_named_version_insert(struct list_head *head, void *new) +{ + struct list_head *i; + u_int8_t ver, new_ver; + + list_for_each(i, head) { + ver = i + sizeof(list_head) + NAMELEN_TARGET_MATCH_MAXLEN; + new_ver = i + sizeof(list_head) + NAMELEN_TARGET_MATCH_MAXLEN; + if (__list_cmp_name(i, new + sizeof(struct list_head)) + && ver == new_ver) + return 0; + } + list_prepend(head, new); + return 1; +} + /* Find this named element in the list. */ #define list_named_find(head, name) \ LIST_FIND(head, __list_cmp_name, void *, name) ===== net/ipv4/netfilter/ip_tables.c 1.34 vs edited ===== --- 1.34/net/ipv4/netfilter/ip_tables.c 2004-11-16 00:00:45 +01:00 +++ edited/net/ipv4/netfilter/ip_tables.c 2004-11-26 23:13:48 +01:00 @@ -1339,7 +1339,7 @@ if (ret != 0) return ret; - if (!list_named_insert(&ipt_target, target)) { + if (!list_named_version_insert(&ipt_target, target)) { duprintf("ipt_register_target: `%s' already in list!\n", target->name); ret = -EINVAL; @@ -1365,7 +1365,7 @@ if (ret != 0) return ret; - if (!list_named_insert(&ipt_match, match)) { + if (!list_named_version_insert(&ipt_match, match)) { duprintf("ipt_register_match: `%s' already in list!\n", match->name); ret = -EINVAL; ^ permalink raw reply [flat|nested] 8+ messages in thread
* New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) 2004-11-26 22:58 ` Pablo Neira @ 2004-11-27 10:45 ` Sven Anders 2004-11-27 14:14 ` Bart De Schuymer ` (2 more replies) 2004-12-07 21:20 ` [PATCH 1/2] ipt_MARK extension with backwards compatibility (kernel side) Pablo Neira 1 sibling, 3 replies; 8+ messages in thread From: Sven Anders @ 2004-11-27 10:45 UTC (permalink / raw) To: netfilter-devel [-- Attachment #1: Type: text/plain, Size: 1651 bytes --] -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Pablo Neira wrote: | My idea, I don't know how crazy it is. Instead of using the size to | guess the target/match version, we could steal 1 byte from char name[] | to define a new field called version, so we could register different | versions of a match/target. Once again, we need a field more... Wasn't there an suggestion to reuse the 'nfcache' field too?? Wasn't the need to an unique rule id posted? What more??? Why not break compatibilty, if it hamper the development? Admit it, the design has some flaws, why not eliminating them? You can not preserve the compatibility forever! It you do it NOW (in the next 2.6 kernel release) you can rely on the circumstance, that it will updated, because in the current kernel cycle, it will be done more often. The longer you wait, the more difficult it will be! To prevent further incompatibility, you can insert some reserved fields to the main structure... Comments welcome :-) Regards ~ Sven - -- ~ Sven Anders <anders@anduras.de> ~ ANDURAS service solutions AG ~ Innstraße 71 - 94036 Passau - Germany ~ Web: www.anduras.de - Tel: +49 (0)851-4 90 50-0 - Fax: +49 (0)851-4 90 50-55 Rechtsform: Aktiengesellschaft - Sitz: Passau - Amtsgericht Passau HRB 6032 Mitglieder des Vorstands: Sven Anders, Marcus Junker, Michael Schön Vorsitzender des Aufsichtsrats: Dipl. Kfm. Karlheinz Antesberger -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.5 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD4DBQFBqFrD5lKZ7Feg4EcRAohvAKCD53V3uhC/b2EBWQvjSlHzKQdXrQCYu7iy FnXEAMJ0SKVKwID2d3yUIw== =2wlB -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) 2004-11-27 10:45 ` New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) Sven Anders @ 2004-11-27 14:14 ` Bart De Schuymer 2004-11-28 20:45 ` New iptables structure Pablo Neira 2004-11-29 12:27 ` New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) Henrik Nordstrom 2 siblings, 0 replies; 8+ messages in thread From: Bart De Schuymer @ 2004-11-27 14:14 UTC (permalink / raw) To: Sven Anders, netfilter-devel On Saturday 27 November 2004 11:45, Sven Anders wrote: > Pablo Neira wrote: > | My idea, I don't know how crazy it is. Instead of using the size to > | guess the target/match version, we could steal 1 byte from char name[] > | to define a new field called version, so we could register different > | versions of a match/target. > > Once again, we need a field more... > Wasn't there an suggestion to reuse the 'nfcache' field too?? > Wasn't the need to an unique rule id posted? > What more??? > > Why not break compatibilty, if it hamper the development? Rusty's solution allows backwards compatibility and adding new features. Your suggestion only allows adding new features. Furthermore, both solutions add the same kind of code complexity. A unique rule id per table is easily constructed. As all the rules of the chains are located after each other, one can just use the number of previous rules, or the address offset from the first rule. Ergo, backwards compatibility need not be broken. cheers, Bart ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: New iptables structure 2004-11-27 10:45 ` New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) Sven Anders 2004-11-27 14:14 ` Bart De Schuymer @ 2004-11-28 20:45 ` Pablo Neira 2004-11-29 12:27 ` New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) Henrik Nordstrom 2 siblings, 0 replies; 8+ messages in thread From: Pablo Neira @ 2004-11-28 20:45 UTC (permalink / raw) To: Sven Anders; +Cc: netfilter-devel, Bart De Schuymer Sven Anders wrote: > Why not break compatibilty, if it hamper the development? I don't see things that way, compatibility could be broken if all developers get their brains broken or become insane because they aren't able to workaround a problem. That didn't happen at the moment :) > To prevent further incompatibility, you can insert some reserved > fields to the main > structure... it's not that easy, you can't always guess where they will come from. So we can't reserve a field in every structure. I agree with Bart, backward compatibility is important. -- Pablo ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) 2004-11-27 10:45 ` New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) Sven Anders 2004-11-27 14:14 ` Bart De Schuymer 2004-11-28 20:45 ` New iptables structure Pablo Neira @ 2004-11-29 12:27 ` Henrik Nordstrom 2 siblings, 0 replies; 8+ messages in thread From: Henrik Nordstrom @ 2004-11-29 12:27 UTC (permalink / raw) To: Sven Anders; +Cc: netfilter-devel On Sat, 27 Nov 2004, Sven Anders wrote: > -----BEGIN PGP SIGNED MESSAGE----- > > Once again, we need a field more... Yes, but in a completely different place, this time in a manner which can be done without too much disturbance, and at the same time building a good framework to allow targets & matches to evolve (which has not been possible up to now). > Wasn't there an suggestion to reuse the 'nfcache' field too?? this because the core kernel does not allow us to add more skb fields than there are today. Not related to what is being discussed now. Modifying the SKB structure is simply not an option unless there is extremely good reasons why. > Wasn't the need to an unique rule id posted? It was, and as a compromise we now have the COMMENT match. > Why not break compatibilty, if it hamper the development? We can within POM, but not that easily in the main kernel. > Admit it, the design has some flaws, why not eliminating them? You can > not preserve the compatibility forever! This is what is being done with the pkttables design. Just takes a bit longer to get there than desireable.. Regards Henrik ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] ipt_MARK extension with backwards compatibility (kernel side). 2004-11-26 22:58 ` Pablo Neira 2004-11-27 10:45 ` New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) Sven Anders @ 2004-12-07 21:20 ` Pablo Neira 2004-12-08 5:44 ` Rusty Russell 1 sibling, 1 reply; 8+ messages in thread From: Pablo Neira @ 2004-12-07 21:20 UTC (permalink / raw) To: Pablo Neira Cc: Anders Fugmann, Bart De Schuymer, Rusty Russell, Netfilter development mailing list [-- Attachment #1: Type: text/plain, Size: 1401 bytes --] Pablo Neira wrote: >> 2) If not, you must extend the size of the structure, so old kernels >> will fail, and new kernels will be able to tell whether they are to use >> the new or old structure. The IPT_ALIGN'ed size of the structure must >> change for this to work! > > > My idea, I don't know how crazy it is. Instead of using the size to > guess the target/match version, we could steal 1 byte from char name[] > to define a new field called version, so we could register different > versions of a match/target. > > Possible scenarios: > a) Old kernel, new iptables binary: since names are manipulated with > str* functions, it shouldn't be any problem with the version stuff > because it will be ignored since info after first '\0' is ignored. > b) New kernel, old iptables: version value is zero, so kernel guess > that it must handle the thing with first version of the target/match. I finally found some spare time to go back this issue, I've finished two patches for the kernel part of my idea of adding versions to targets/matches. One for ip_tables, and other for ipt_MARK, this based on Rusty's. iptables (user space) patches is still missing :( It works for me (TM) on a x86/gcc-2.95 with both patches applied and using an old binary version of iptables to test that doesn't break backward compatibility. Please, say crap/cool/dirty/crazy/whatever about this. -- Pablo [-- Attachment #2: ip_table-version.patch --] [-- Type: text/x-patch, Size: 6541 bytes --] ===== include/linux/netfilter_ipv4/ip_tables.h 1.12 vs edited ===== --- 1.12/include/linux/netfilter_ipv4/ip_tables.h 2004-11-02 01:39:53 +01:00 +++ edited/include/linux/netfilter_ipv4/ip_tables.h 2004-12-07 20:16:50 +01:00 @@ -53,7 +53,9 @@ u_int16_t match_size; /* Used by userspace */ - char name[IPT_FUNCTION_MAXNAMELEN]; + char name[IPT_FUNCTION_MAXNAMELEN-1]; + + u_int8_t version; } user; struct { u_int16_t match_size; @@ -76,7 +78,9 @@ u_int16_t target_size; /* Used by userspace */ - char name[IPT_FUNCTION_MAXNAMELEN]; + char name[IPT_FUNCTION_MAXNAMELEN-1]; + + u_int8_t version; } user; struct { u_int16_t target_size; @@ -344,7 +348,9 @@ { struct list_head list; - const char name[IPT_FUNCTION_MAXNAMELEN]; + const char name[IPT_FUNCTION_MAXNAMELEN-1]; + + u_int8_t version; /* Return true or false: return FALSE and set *hotdrop = 1 to force immediate packet drop. */ @@ -378,7 +384,9 @@ { struct list_head list; - const char name[IPT_FUNCTION_MAXNAMELEN]; + const char name[IPT_FUNCTION_MAXNAMELEN-1]; + + u_int8_t version; /* Called when user tries to insert an entry of this type: hook_mask is a bitmask of hooks from which it can be @@ -414,7 +422,7 @@ extern void ipt_unregister_match(struct ipt_match *match); extern struct ipt_target * -__ipt_find_target_lock(const char *name, int *error); +__ipt_find_target_lock(const char *name, const u_int8_t ver, int *error); extern void __ipt_mutex_up(void); /* Furniture shopping... */ ===== net/ipv4/netfilter/ip_tables.c 1.34 vs edited ===== --- 1.34/net/ipv4/netfilter/ip_tables.c 2004-11-16 00:00:45 +01:00 +++ edited/net/ipv4/netfilter/ip_tables.c 2004-12-07 20:07:45 +01:00 @@ -465,22 +465,133 @@ return find_inlist_lock(&ipt_tables, name, "iptable_", error, mutex); } +static struct ipt_target * +find_target(const char *name, u_int8_t version) +{ + struct list_head *i; + struct ipt_target *t; + + list_for_each(i, &ipt_target) { + t = (struct ipt_target *) i; + if (!strcmp(name, t->name) + && version == t->version) + return t; + } + return NULL; +} + +static struct ipt_match * +find_match(const char *name, u_int8_t version) +{ + struct list_head *i; + struct ipt_match *m; + + list_for_each(i, &ipt_match) { + m = (struct ipt_match *) i; + if (!strcmp(name, m->name) + && version == m->version) + return m; + } + return NULL; +} + +static int +target_insert(struct ipt_target *target) +{ + if (find_target(target->name, target->version) == NULL) { + list_prepend(&ipt_target, target); + return 1; + } + return 0; +} + +static int +match_insert(struct ipt_match *match) +{ + if (find_match(match->name, match->version) == NULL) { + list_prepend(&ipt_match, match); + return 1; + } + return 0; +} + +#define IPT_MATCH 0 +#define IPT_TARGET 1 + +static inline void * +find_inlist_tm_lock_noload(const char *name, + const u_int8_t ver, + int *error, + struct semaphore *mutex, + int type) +{ + void *ret = NULL; + + *error = down_interruptible(mutex); + if (*error != 0) + return NULL; + + switch(type) { + case IPT_MATCH: + ret = (void *) find_match(name, ver); + break; + case IPT_TARGET: + ret = (void *) find_target(name, ver); + break; + default: + /* shouldn't happen */ + break; + } + if (!ret) { + printk("find_tm_lock_noload: `%s' version=(%1x) not found!\n", name, ver); + *error = -ENOENT; + up(mutex); + } + return ret; +} + +#ifndef CONFIG_KMOD +#define find_inlist_tm_lock(n,v,p,e,m,t) find_inlist_tm_lock_noload((n),(v),(e),(m),(t)) +#else +static void * +find_inlist_tm_lock(const char *name, + const u_int8_t ver, + const char *prefix, + int *error, + struct semaphore *mutex, + int type) +{ + void *ret; + + ret = find_inlist_tm_lock_noload(name, ver, error, mutex, type); + if (!ret) { + duprintf("find_inlist: loading `%s%s'.\n", prefix, name); + request_module("%s%s", prefix, name); + ret = find_inlist_tm_lock_noload(name, ver, error, mutex,type); + } + + return ret; +} +#endif + static inline struct ipt_match * -find_match_lock(const char *name, int *error, struct semaphore *mutex) +find_match_lock(const char *name, u_int8_t ver, int *error, + struct semaphore *mutex) { - return find_inlist_lock(&ipt_match, name, "ipt_", error, mutex); + return find_inlist_tm_lock(name, ver, "ipt_", error, mutex, IPT_MATCH); } static struct ipt_target * -ipt_find_target_lock(const char *name, int *error, struct semaphore *mutex) +ipt_find_target_lock(const char *name, const u_int8_t ver, int *error, + struct semaphore *mutex) { - return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex); + return find_inlist_tm_lock(name, ver, "ipt_", error, mutex,IPT_TARGET); } struct ipt_target * -__ipt_find_target_lock(const char *name, int *error) +__ipt_find_target_lock(const char *name, const u_int8_t ver, int *error) { - return ipt_find_target_lock(name,error,&ipt_mutex); + return ipt_find_target_lock(name,ver,error,&ipt_mutex); } void @@ -651,7 +762,8 @@ int ret; struct ipt_match *match; - match = find_match_lock(m->u.user.name, &ret, &ipt_mutex); + match = find_match_lock(m->u.user.name, m->u.user.version, &ret, + &ipt_mutex); if (!match) { duprintf("check_match: `%s' not found\n", m->u.user.name); return ret; @@ -699,7 +811,8 @@ goto cleanup_matches; t = ipt_get_target(e); - target = ipt_find_target_lock(t->u.user.name, &ret, &ipt_mutex); + target = ipt_find_target_lock(t->u.user.name, t->u.user.version, &ret, + &ipt_mutex); if (!target) { duprintf("check_entry: `%s' not found\n", t->u.user.name); goto cleanup_matches; @@ -1339,12 +1452,13 @@ if (ret != 0) return ret; - if (!list_named_insert(&ipt_target, target)) { - duprintf("ipt_register_target: `%s' already in list!\n", - target->name); - ret = -EINVAL; + if (!target_insert(target)) { + printk("ipt_register_target: `%s' already in list!\n", + target->name); + return -EINVAL; } up(&ipt_mutex); + printk("register_target: `%s' registered\n", target->name); return ret; } @@ -1365,12 +1479,13 @@ if (ret != 0) return ret; - if (!list_named_insert(&ipt_match, match)) { - duprintf("ipt_register_match: `%s' already in list!\n", - match->name); - ret = -EINVAL; + if (!match_insert(match)) { + printk("ipt_register_match: `%s' already in list!\n", + match->name); + return -EINVAL; } up(&ipt_mutex); + printk("register_match: `%s' registered\n", match->name); return ret; } [-- Attachment #3: ipt_mark.patch --] [-- Type: text/x-patch, Size: 4685 bytes --] ===== include/linux/netfilter_ipv4/ipt_MARK.h 1.1 vs edited ===== --- 1.1/include/linux/netfilter_ipv4/ipt_MARK.h 2002-02-05 18:39:43 +01:00 +++ edited/include/linux/netfilter_ipv4/ipt_MARK.h 2004-12-07 21:17:33 +01:00 @@ -1,8 +1,19 @@ #ifndef _IPT_MARK_H_target #define _IPT_MARK_H_target -struct ipt_mark_target_info { +struct ipt_mark_target_info_v0 { unsigned long mark; +}; + +enum { + IPT_MARK_SET=0, + IPT_MARK_AND, + IPT_MARK_OR +}; + +struct ipt_mark_target_info_v1 { + unsigned long mark; + u_int8_t mode; }; #endif /*_IPT_MARK_H_target*/ ===== net/ipv4/netfilter/ipt_MARK.c 1.7 vs edited ===== --- 1.7/net/ipv4/netfilter/ipt_MARK.c 2004-01-30 02:00:13 +01:00 +++ edited/net/ipv4/netfilter/ipt_MARK.c 2004-12-07 21:29:03 +01:00 @@ -20,14 +20,14 @@ MODULE_DESCRIPTION("iptables MARK modification module"); static unsigned int -target(struct sk_buff **pskb, - const struct net_device *in, - const struct net_device *out, - unsigned int hooknum, - const void *targinfo, - void *userinfo) +target_v0(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const void *targinfo, + void *userinfo) { - const struct ipt_mark_target_info *markinfo = targinfo; + const struct ipt_mark_target_info_v0 *markinfo = targinfo; if((*pskb)->nfmark != markinfo->mark) { (*pskb)->nfmark = markinfo->mark; @@ -36,43 +36,118 @@ return IPT_CONTINUE; } +static unsigned int +target_v1(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const void *targinfo, + void *userinfo) +{ + const struct ipt_mark_target_info_v1 *markinfo = targinfo; + int mark = 0; + + switch (markinfo->mode) { + case IPT_MARK_SET: + mark = markinfo->mark; + break; + + case IPT_MARK_AND: + mark = (*pskb)->nfmark & markinfo->mark; + break; + + case IPT_MARK_OR: + mark = (*pskb)->nfmark | markinfo->mark; + break; + } + + if((*pskb)->nfmark != mark) { + (*pskb)->nfmark = mark; + (*pskb)->nfcache |= NFC_ALTERED; + } + return IPT_CONTINUE; +} + static int -checkentry(const char *tablename, - const struct ipt_entry *e, - void *targinfo, - unsigned int targinfosize, - unsigned int hook_mask) +checkentry_v0(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) { - if (targinfosize != IPT_ALIGN(sizeof(struct ipt_mark_target_info))) { + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + + if (targinfosize + != IPT_ALIGN(sizeof(struct ipt_mark_target_info_v0))) { printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n", targinfosize, - IPT_ALIGN(sizeof(struct ipt_mark_target_info))); + IPT_ALIGN(sizeof(struct ipt_mark_target_info_v0))); return 0; } + return 1; +} + +static struct ipt_target ipt_mark_reg_v0 = { + .name = "MARK", + .target = target_v0, + .checkentry = checkentry_v0, + .me = THIS_MODULE, +}; + +static int +checkentry_v1(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + const struct ipt_mark_target_info_v1 *markinfo = targinfo; if (strcmp(tablename, "mangle") != 0) { printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename); return 0; } + + if (targinfosize + != IPT_ALIGN(sizeof(struct ipt_mark_target_info_v1))) { + printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_mark_target_info_v1))); + return 0; + } + if (markinfo->mode != IPT_MARK_SET + && markinfo->mode != IPT_MARK_AND + && markinfo->mode != IPT_MARK_OR) { + printk(KERN_WARNING "MARK: unknown mode %u\n", + markinfo->mode); + return 0; + } return 1; } -static struct ipt_target ipt_mark_reg = { +static struct ipt_target ipt_mark_reg_v1 = { .name = "MARK", - .target = target, - .checkentry = checkentry, + .version = 0x1, + .target = target_v1, + .checkentry = checkentry_v1, .me = THIS_MODULE, }; static int __init init(void) { - return ipt_register_target(&ipt_mark_reg); + if (ipt_register_target(&ipt_mark_reg_v0) < 0) + return -EINVAL; + return ipt_register_target(&ipt_mark_reg_v1); } static void __exit fini(void) { - ipt_unregister_target(&ipt_mark_reg); + ipt_unregister_target(&ipt_mark_reg_v0); + ipt_unregister_target(&ipt_mark_reg_v1); } module_init(init); ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] ipt_MARK extension with backwards compatibility (kernel side). 2004-12-07 21:20 ` [PATCH 1/2] ipt_MARK extension with backwards compatibility (kernel side) Pablo Neira @ 2004-12-08 5:44 ` Rusty Russell 0 siblings, 0 replies; 8+ messages in thread From: Rusty Russell @ 2004-12-08 5:44 UTC (permalink / raw) To: Pablo Neira Cc: Anders Fugmann, Netfilter development mailing list, Bart De Schuymer On Tue, 2004-12-07 at 22:20 +0100, Pablo Neira wrote: > Pablo Neira wrote: > > >> 2) If not, you must extend the size of the structure, so old kernels > >> will fail, and new kernels will be able to tell whether they are to use > >> the new or old structure. The IPT_ALIGN'ed size of the structure must > >> change for this to work! > > > > > > My idea, I don't know how crazy it is. Instead of using the size to > > guess the target/match version, we could steal 1 byte from char name[] > > to define a new field called version, so we could register different > > versions of a match/target. > > > > Possible scenarios: > > a) Old kernel, new iptables binary: since names are manipulated with > > str* functions, it shouldn't be any problem with the version stuff > > because it will be ignored since info after first '\0' is ignored. > > b) New kernel, old iptables: version value is zero, so kernel guess > > that it must handle the thing with first version of the target/match. > > > I finally found some spare time to go back this issue, I've finished two > patches for the kernel part of my idea of adding versions to > targets/matches. One for ip_tables, and other for ipt_MARK, this based > on Rusty's. This is so evil that my first reaction was to say "ick!". My second reaction was to say "cool"!. My third reaction was "ick!" again. > iptables (user space) patches is still missing :( OK. For the other variant, I wrote a userspace patch, built it, and used nfsim to test it. Unfortunately, SVN is having trouble at the moment, so the test script I used is below (use env var NFSIM_IPTABLES_PREFIX to override /sbin for iptables) If you ensure that works, I'm relatively happy with this. Rusty. # Test the ipt_MARK target, which has a backwards compatbility mode. # Test old-style first, insert and delete. iptables -t mangle -A PREROUTING -j MARK --set-mark 7 iptables -t mangle -D PREROUTING -j MARK --set-mark 7 iptables -t mangle -A PREROUTING -s 192.160.0.2 -j MARK --set-mark 7 iptables -t mangle -D PREROUTING -s 192.160.0.2 -j MARK --set-mark 7 # Test that it works. iptables -t mangle -A PREROUTING -j MARK --set-mark 7 expect gen_ip send:eth1 MARK 7 {IPv4 192.168.0.2 192.168.1.2 10 17 1 2} gen_ip IF=eth0 192.168.0.2 192.168.1.2 10 17 1 2 iptables -t mangle -D PREROUTING -j MARK --set-mark 7 # Test new-style, insert and delete. iptables -t mangle -A PREROUTING -j MARK --or-mark 7 iptables -t mangle -D PREROUTING -j MARK --or-mark 7 iptables -t mangle -A PREROUTING -j MARK --and-mark 7 iptables -t mangle -D PREROUTING -j MARK --and-mark 7 iptables -t mangle -A PREROUTING -s 192.160.0.2 -j MARK --or-mark 7 iptables -t mangle -D PREROUTING -s 192.160.0.2 -j MARK --or-mark 7 iptables -t mangle -A PREROUTING -s 192.160.0.2 -j MARK --and-mark 7 iptables -t mangle -D PREROUTING -s 192.160.0.2 -j MARK --and-mark 7 # Test that they work. iptables -t mangle -A PREROUTING -j MARK --or-mark 7 expect gen_ip send:eth1 MARK 7 {IPv4 192.168.0.2 192.168.1.2 10 17 1 2} gen_ip IF=eth0 192.168.0.2 192.168.1.2 10 17 1 2 iptables -t mangle -D PREROUTING -j MARK --or-mark 7 iptables -t mangle -A PREROUTING -j MARK --set-mark 3 iptables -t mangle -A PREROUTING -j MARK --or-mark 4 expect gen_ip send:eth1 MARK 7 {IPv4 192.168.0.2 192.168.1.2 10 17 1 2} gen_ip IF=eth0 192.168.0.2 192.168.1.2 10 17 1 2 iptables -t mangle -D PREROUTING -j MARK --set-mark 3 iptables -t mangle -D PREROUTING -j MARK --or-mark 4 iptables -t mangle -A PREROUTING -j MARK --set-mark 3 iptables -t mangle -A PREROUTING -j MARK --and-mark 6 expect gen_ip send:eth1 MARK 2 {IPv4 192.168.0.2 192.168.1.2 10 17 1 2} gen_ip IF=eth0 192.168.0.2 192.168.1.2 10 17 1 2 iptables -t mangle -D PREROUTING -j MARK --set-mark 3 iptables -t mangle -D PREROUTING -j MARK --and-mark 6 # Now mix them up: check we delete the right one. iptables -t mangle -A PREROUTING -j MARK --set-mark 7 iptables -t mangle -A PREROUTING -j MARK --or-mark 7 iptables -t mangle -A PREROUTING -j MARK --and-mark 7 # Delete old-style. iptables -t mangle -D PREROUTING -j MARK --set-mark 7 expect iptables iptables: command failed iptables -t mangle -D PREROUTING -j MARK --set-mark 7 iptables -t mangle -A PREROUTING -j MARK --set-mark 7 # Delete or. iptables -t mangle -D PREROUTING -j MARK --or-mark 7 expect iptables iptables: command failed iptables -t mangle -D PREROUTING -j MARK --or-mark 7 iptables -t mangle -A PREROUTING -j MARK --or-mark 7 # Delete and. iptables -t mangle -D PREROUTING -j MARK --and-mark 7 expect iptables iptables: command failed iptables -t mangle -D PREROUTING -j MARK --and-mark 7 iptables -t mangle -A PREROUTING -j MARK --and-mark 7 -- A bad analogy is like a leaky screwdriver -- Richard Braakman ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2004-12-08 5:44 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2004-11-25 4:49 [PATCH 1/2] ipt_MARK extension with backwards compatibility (kernel side) Rusty Russell 2004-11-26 22:58 ` Pablo Neira 2004-11-27 10:45 ` New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) Sven Anders 2004-11-27 14:14 ` Bart De Schuymer 2004-11-28 20:45 ` New iptables structure Pablo Neira 2004-11-29 12:27 ` New iptables structure (was: [PATCH 1/2] ipt_MARK extension with backwards compatibilty...) Henrik Nordstrom 2004-12-07 21:20 ` [PATCH 1/2] ipt_MARK extension with backwards compatibility (kernel side) Pablo Neira 2004-12-08 5:44 ` Rusty Russell
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.