All of lore.kernel.org
 help / color / mirror / Atom feed
* [NETFILTER 00/04]: Netfilter Update
@ 2006-03-31  1:09 Patrick McHardy
  2006-03-31  1:09 ` [NETFILTER 01/04]: x_tables: unify IPv4/IPv6 multiport match Patrick McHardy
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Patrick McHardy @ 2006-03-31  1:09 UTC (permalink / raw)
  To: davem; +Cc: netfilter-devel, Patrick McHardy

Hi Dave,

following are my netfilter patches for 2.6.17. The "fix expectation
notifier unregistration" should go in -stable too, I'll send it
there separately. Please apply.


 include/linux/netfilter/x_tables.h            |   67 +
 include/linux/netfilter/xt_multiport.h        |   30 
 include/linux/netfilter_ipv4/ip_tables.h      |   18 
 include/linux/netfilter_ipv4/ipt_multiport.h  |   31 
 include/linux/netfilter_ipv6/ip6t_multiport.h |   25 
 net/compat.c                                  |    3 
 net/ipv4/netfilter/Kconfig                    |   10 
 net/ipv4/netfilter/Makefile                   |    1 
 net/ipv4/netfilter/ip_conntrack_netlink.c     |    2 
 net/ipv4/netfilter/ip_tables.c                | 1286 +++++++++++++++++++++-----
 net/ipv4/netfilter/ipt_multiport.c            |  195 ---
 net/ipv6/netfilter/Kconfig                    |   10 
 net/ipv6/netfilter/Makefile                   |    1 
 net/ipv6/netfilter/ip6t_multiport.c           |  125 --
 net/netfilter/Kconfig                         |   10 
 net/netfilter/Makefile                        |    1 
 net/netfilter/nf_conntrack_netlink.c          |    6 
 net/netfilter/x_tables.c                      |  113 ++
 net/netfilter/xt_multiport.c                  |  314 ++++++
 19 files changed, 1656 insertions(+), 592 deletions(-)

Dmitry Mishin:
      [NETFILTER]: iptables 32bit compat layer

Martin Josefsson:
      [NETFILTER]: fix ifdef for connmark support in nf_conntrack_netlink
      [NETFILTER]: {ip,nf}_conntrack_netlink: fix expectation notifier unregistration

Yasuyuki Kozakai:
      [NETFILTER]: x_tables: unify IPv4/IPv6 multiport match

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [NETFILTER 01/04]: x_tables: unify IPv4/IPv6 multiport match
  2006-03-31  1:09 [NETFILTER 00/04]: Netfilter Update Patrick McHardy
@ 2006-03-31  1:09 ` Patrick McHardy
  2006-03-31  1:09 ` [NETFILTER 02/04]: fix ifdef for connmark support in nf_conntrack_netlink Patrick McHardy
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Patrick McHardy @ 2006-03-31  1:09 UTC (permalink / raw)
  To: davem; +Cc: netfilter-devel, Patrick McHardy

[NETFILTER]: x_tables: unify IPv4/IPv6 multiport match

This unifies ipt_multiport and ip6t_multiport to xt_multiport.
As a result, this addes support for inversion and port range match
to IPv6 packets.

Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit 4d5ee8549d2385d700967246fb8ff6cc1828ceb1
tree 6d3915db257ab1cb3b15cfc7afa341f3841a2f1b
parent 6b0b3ab9f047358723d8b3116b71318f64088a1a
author Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp> Wed, 29 Mar 2006 10:07:52 +0200
committer Patrick McHardy <kaber@trash.net> Wed, 29 Mar 2006 10:07:52 +0200

 include/linux/netfilter/xt_multiport.h        |   30 ++
 include/linux/netfilter_ipv4/ipt_multiport.h  |   31 +-
 include/linux/netfilter_ipv6/ip6t_multiport.h |   25 +-
 net/ipv4/netfilter/Kconfig                    |   10 -
 net/ipv4/netfilter/Makefile                   |    1 
 net/ipv4/netfilter/ipt_multiport.c            |  195 ----------------
 net/ipv6/netfilter/Kconfig                    |   10 -
 net/ipv6/netfilter/Makefile                   |    1 
 net/ipv6/netfilter/ip6t_multiport.c           |  125 ----------
 net/netfilter/Kconfig                         |   10 +
 net/netfilter/Makefile                        |    1 
 net/netfilter/xt_multiport.c                  |  314 +++++++++++++++++++++++++
 12 files changed, 372 insertions(+), 381 deletions(-)

diff --git a/include/linux/netfilter/xt_multiport.h b/include/linux/netfilter/xt_multiport.h
new file mode 100644
index 0000000..d49ee41
--- /dev/null
+++ b/include/linux/netfilter/xt_multiport.h
@@ -0,0 +1,30 @@
+#ifndef _XT_MULTIPORT_H
+#define _XT_MULTIPORT_H
+
+enum xt_multiport_flags
+{
+	XT_MULTIPORT_SOURCE,
+	XT_MULTIPORT_DESTINATION,
+	XT_MULTIPORT_EITHER
+};
+
+#define XT_MULTI_PORTS	15
+
+/* Must fit inside union xt_matchinfo: 16 bytes */
+struct xt_multiport
+{
+	u_int8_t flags;				/* Type of comparison */
+	u_int8_t count;				/* Number of ports */
+	u_int16_t ports[XT_MULTI_PORTS];	/* Ports */
+};
+
+struct xt_multiport_v1
+{
+	u_int8_t flags;				/* Type of comparison */
+	u_int8_t count;				/* Number of ports */
+	u_int16_t ports[XT_MULTI_PORTS];	/* Ports */
+	u_int8_t pflags[XT_MULTI_PORTS];	/* Port flags */
+	u_int8_t invert;			/* Invert flag */
+};
+
+#endif /*_XT_MULTIPORT_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_multiport.h b/include/linux/netfilter_ipv4/ipt_multiport.h
index e6b6fff..55fe85e 100644
--- a/include/linux/netfilter_ipv4/ipt_multiport.h
+++ b/include/linux/netfilter_ipv4/ipt_multiport.h
@@ -1,30 +1,15 @@
 #ifndef _IPT_MULTIPORT_H
 #define _IPT_MULTIPORT_H
-#include <linux/netfilter_ipv4/ip_tables.h>
 
-enum ipt_multiport_flags
-{
-	IPT_MULTIPORT_SOURCE,
-	IPT_MULTIPORT_DESTINATION,
-	IPT_MULTIPORT_EITHER
-};
+#include <linux/netfilter/xt_multiport.h>
 
-#define IPT_MULTI_PORTS	15
+#define IPT_MULTIPORT_SOURCE		XT_MULTIPORT_SOURCE
+#define IPT_MULTIPORT_DESTINATION	XT_MULTIPORT_DESTINATION
+#define IPT_MULTIPORT_EITHER		XT_MULTIPORT_EITHER
 
-/* Must fit inside union ipt_matchinfo: 16 bytes */
-struct ipt_multiport
-{
-	u_int8_t flags;				/* Type of comparison */
-	u_int8_t count;				/* Number of ports */
-	u_int16_t ports[IPT_MULTI_PORTS];	/* Ports */
-};
+#define IPT_MULTI_PORTS			XT_MULTI_PORTS
+
+#define ipt_multiport			xt_multiport
+#define ipt_multiport_v1		xt_multiport_v1
 
-struct ipt_multiport_v1
-{
-	u_int8_t flags;				/* Type of comparison */
-	u_int8_t count;				/* Number of ports */
-	u_int16_t ports[IPT_MULTI_PORTS];	/* Ports */
-	u_int8_t pflags[IPT_MULTI_PORTS];	/* Port flags */
-	u_int8_t invert;			/* Invert flag */
-};
 #endif /*_IPT_MULTIPORT_H*/
diff --git a/include/linux/netfilter_ipv6/ip6t_multiport.h b/include/linux/netfilter_ipv6/ip6t_multiport.h
index efe4954..042c926 100644
--- a/include/linux/netfilter_ipv6/ip6t_multiport.h
+++ b/include/linux/netfilter_ipv6/ip6t_multiport.h
@@ -1,21 +1,14 @@
 #ifndef _IP6T_MULTIPORT_H
 #define _IP6T_MULTIPORT_H
-#include <linux/netfilter_ipv6/ip6_tables.h>
 
-enum ip6t_multiport_flags
-{
-	IP6T_MULTIPORT_SOURCE,
-	IP6T_MULTIPORT_DESTINATION,
-	IP6T_MULTIPORT_EITHER
-};
+#include <linux/netfilter/xt_multiport.h>
 
-#define IP6T_MULTI_PORTS	15
+#define IP6T_MULTIPORT_SOURCE		XT_MULTIPORT_SOURCE
+#define IP6T_MULTIPORT_DESTINATION	XT_MULTIPORT_DESTINATION
+#define IP6T_MULTIPORT_EITHER		XT_MULTIPORT_EITHER
 
-/* Must fit inside union ip6t_matchinfo: 16 bytes */
-struct ip6t_multiport
-{
-	u_int8_t flags;				/* Type of comparison */
-	u_int8_t count;				/* Number of ports */
-	u_int16_t ports[IP6T_MULTI_PORTS];	/* Ports */
-};
-#endif /*_IPT_MULTIPORT_H*/
+#define IP6T_MULTI_PORTS		XT_MULTI_PORTS
+
+#define ip6t_multiport			xt_multiport
+
+#endif /*_IP6T_MULTIPORT_H*/
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index ebbd644..77855cc 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -221,16 +221,6 @@ config IP_NF_MATCH_IPRANGE
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_MATCH_MULTIPORT
-	tristate "Multiple port match support"
-	depends on IP_NF_IPTABLES
-	help
-	  Multiport matching allows you to match TCP or UDP packets based on
-	  a series of source or destination ports: normally a rule can only
-	  match a single range of ports.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_TOS
 	tristate "TOS match support"
 	depends on IP_NF_IPTABLES
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 09ae167..461cb1e 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -53,7 +53,6 @@ obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
 # matches
 obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o
 obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
-obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
diff --git a/net/ipv4/netfilter/ipt_multiport.c b/net/ipv4/netfilter/ipt_multiport.c
deleted file mode 100644
index ac95d83..0000000
--- a/net/ipv4/netfilter/ipt_multiport.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/* Kernel module to match one of a list of TCP/UDP ports: ports are in
-   the same place so we can treat them as equal. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/udp.h>
-#include <linux/skbuff.h>
-
-#include <linux/netfilter_ipv4/ipt_multiport.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-MODULE_DESCRIPTION("iptables multiple port match module");
-
-#if 0
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
-/* Returns 1 if the port is matched by the test, 0 otherwise. */
-static inline int
-ports_match(const u_int16_t *portlist, enum ipt_multiport_flags flags,
-	    u_int8_t count, u_int16_t src, u_int16_t dst)
-{
-	unsigned int i;
-	for (i=0; i<count; i++) {
-		if (flags != IPT_MULTIPORT_DESTINATION
-		    && portlist[i] == src)
-			return 1;
-
-		if (flags != IPT_MULTIPORT_SOURCE
-		    && portlist[i] == dst)
-			return 1;
-	}
-
-	return 0;
-}
-
-/* Returns 1 if the port is matched by the test, 0 otherwise. */
-static inline int
-ports_match_v1(const struct ipt_multiport_v1 *minfo,
-	       u_int16_t src, u_int16_t dst)
-{
-	unsigned int i;
-	u_int16_t s, e;
-
-	for (i=0; i < minfo->count; i++) {
-		s = minfo->ports[i];
-
-		if (minfo->pflags[i]) {
-			/* range port matching */
-			e = minfo->ports[++i];
-			duprintf("src or dst matches with %d-%d?\n", s, e);
-
-			if (minfo->flags == IPT_MULTIPORT_SOURCE
-			    && src >= s && src <= e)
-				return 1 ^ minfo->invert;
-			if (minfo->flags == IPT_MULTIPORT_DESTINATION
-			    && dst >= s && dst <= e)
-				return 1 ^ minfo->invert;
-			if (minfo->flags == IPT_MULTIPORT_EITHER
-			    && ((dst >= s && dst <= e)
-				|| (src >= s && src <= e)))
-				return 1 ^ minfo->invert;
-		} else {
-			/* exact port matching */
-			duprintf("src or dst matches with %d?\n", s);
-
-			if (minfo->flags == IPT_MULTIPORT_SOURCE
-			    && src == s)
-				return 1 ^ minfo->invert;
-			if (minfo->flags == IPT_MULTIPORT_DESTINATION
-			    && dst == s)
-				return 1 ^ minfo->invert;
-			if (minfo->flags == IPT_MULTIPORT_EITHER
-			    && (src == s || dst == s))
-				return 1 ^ minfo->invert;
-		}
-	}
- 
- 	return minfo->invert;
-}
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const struct xt_match *match,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-	u16 _ports[2], *pptr;
-	const struct ipt_multiport *multiinfo = matchinfo;
-
-	if (offset)
-		return 0;
-
-	pptr = skb_header_pointer(skb, protoff,
-				  sizeof(_ports), _ports);
-	if (pptr == NULL) {
-		/* We've been asked to examine this packet, and we
-		 * can't.  Hence, no choice but to drop.
-		 */
-		duprintf("ipt_multiport:"
-			 " Dropping evil offset=0 tinygram.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	return ports_match(multiinfo->ports,
-			   multiinfo->flags, multiinfo->count,
-			   ntohs(pptr[0]), ntohs(pptr[1]));
-}
-
-static int
-match_v1(const struct sk_buff *skb,
-	 const struct net_device *in,
-	 const struct net_device *out,
-	 const struct xt_match *match,
-	 const void *matchinfo,
-	 int offset,
-	 unsigned int protoff,
-	 int *hotdrop)
-{
-	u16 _ports[2], *pptr;
-	const struct ipt_multiport_v1 *multiinfo = matchinfo;
-
-	if (offset)
-		return 0;
-
-	pptr = skb_header_pointer(skb, protoff,
-				  sizeof(_ports), _ports);
-	if (pptr == NULL) {
-		/* We've been asked to examine this packet, and we
-		 * can't.  Hence, no choice but to drop.
-		 */
-		duprintf("ipt_multiport:"
-			 " Dropping evil offset=0 tinygram.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
-}
-
-static struct ipt_match multiport_match = {
-	.name		= "multiport",
-	.revision	= 0,
-	.match		= match,
-	.matchsize	= sizeof(struct ipt_multiport),
-	.me		= THIS_MODULE,
-};
-
-static struct ipt_match multiport_match_v1 = {
-	.name		= "multiport",
-	.revision	= 1,
-	.match		= match_v1,
-	.matchsize	= sizeof(struct ipt_multiport_v1),
-	.me		= THIS_MODULE,
-};
-
-static int __init ipt_multiport_init(void)
-{
-	int err;
-
-	err = ipt_register_match(&multiport_match);
-	if (!err) {
-		err = ipt_register_match(&multiport_match_v1);
-		if (err)
-			ipt_unregister_match(&multiport_match);
-	}
-
-	return err;
-}
-
-static void __exit ipt_multiport_fini(void)
-{
-	ipt_unregister_match(&multiport_match);
-	ipt_unregister_match(&multiport_match_v1);
-}
-
-module_init(ipt_multiport_init);
-module_exit(ipt_multiport_fini);
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index bdd569f..4bc4e5b 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -87,16 +87,6 @@ config IP6_NF_MATCH_HL
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_MULTIPORT
-	tristate "Multiple port match support"
-	depends on IP6_NF_IPTABLES
-	help
-	  Multiport matching allows you to match TCP or UDP packets based on
-	  a series of source or destination ports: normally a rule can only
-	  match a single range of ports.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MATCH_OWNER
 	tristate "Owner match support"
 	depends on IP6_NF_IPTABLES
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index c387170..eeeb57d 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) +=
 obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
-obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
diff --git a/net/ipv6/netfilter/ip6t_multiport.c b/net/ipv6/netfilter/ip6t_multiport.c
deleted file mode 100644
index 10c48ba..0000000
--- a/net/ipv6/netfilter/ip6t_multiport.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/* Kernel module to match one of a list of TCP/UDP ports: ports are in
-   the same place so we can treat them as equal. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/udp.h>
-#include <linux/skbuff.h>
-#include <linux/in.h>
-
-#include <linux/netfilter_ipv6/ip6t_multiport.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-MODULE_DESCRIPTION("ip6tables match for multiple ports");
-
-#if 0
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
-/* Returns 1 if the port is matched by the test, 0 otherwise. */
-static inline int
-ports_match(const u_int16_t *portlist, enum ip6t_multiport_flags flags,
-	    u_int8_t count, u_int16_t src, u_int16_t dst)
-{
-	unsigned int i;
-	for (i=0; i<count; i++) {
-		if (flags != IP6T_MULTIPORT_DESTINATION
-		    && portlist[i] == src)
-			return 1;
-
-		if (flags != IP6T_MULTIPORT_SOURCE
-		    && portlist[i] == dst)
-			return 1;
-	}
-
-	return 0;
-}
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const struct xt_match *match,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-	u16 _ports[2], *pptr;
-	const struct ip6t_multiport *multiinfo = matchinfo;
-
-	/* Must not be a fragment. */
-	if (offset)
-		return 0;
-
-	/* Must be big enough to read ports (both UDP and TCP have
-	   them at the start). */
-	pptr = skb_header_pointer(skb, protoff, sizeof(_ports), &_ports[0]);
-	if (pptr == NULL) {
-		/* We've been asked to examine this packet, and we
-		 * can't.  Hence, no choice but to drop.
-		 */
-		duprintf("ip6t_multiport:"
-			 " Dropping evil offset=0 tinygram.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	return ports_match(multiinfo->ports,
-			   multiinfo->flags, multiinfo->count,
-			   ntohs(pptr[0]), ntohs(pptr[1]));
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-checkentry(const char *tablename,
-	   const void *info,
-	   const struct xt_match *match,
-	   void *matchinfo,
-	   unsigned int matchsize,
-	   unsigned int hook_mask)
-{
-	const struct ip6t_ip6 *ip = info;
-	const struct ip6t_multiport *multiinfo = matchinfo;
-
-	/* Must specify proto == TCP/UDP, no unknown flags or bad count */
-	return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
-		&& !(ip->invflags & IP6T_INV_PROTO)
-		&& (multiinfo->flags == IP6T_MULTIPORT_SOURCE
-		    || multiinfo->flags == IP6T_MULTIPORT_DESTINATION
-		    || multiinfo->flags == IP6T_MULTIPORT_EITHER)
-		&& multiinfo->count <= IP6T_MULTI_PORTS;
-}
-
-static struct ip6t_match multiport_match = {
-	.name		= "multiport",
-	.match		= match,
-	.matchsize	= sizeof(struct ip6t_multiport),
-	.checkentry	= checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init ip6t_multiport_init(void)
-{
-	return ip6t_register_match(&multiport_match);
-}
-
-static void __exit ip6t_multiport_fini(void)
-{
-	ip6t_unregister_match(&multiport_match);
-}
-
-module_init(ip6t_multiport_init);
-module_exit(ip6t_multiport_fini);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 5fe5189..e2893ef 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -298,6 +298,16 @@ config NETFILTER_XT_MATCH_POLICY
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_MATCH_MULTIPORT
+	tristate "Multiple port match support"
+	depends on NETFILTER_XTABLES
+	help
+	  Multiport matching allows you to match TCP or UDP packets based on
+	  a series of source or destination ports: normally a rule can only
+	  match a single range of ports.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_PHYSDEV
 	tristate '"physdev" match support'
 	depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 8f02486..95b7e41 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) 
 obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c
new file mode 100644
index 0000000..0717cbb
--- /dev/null
+++ b/net/netfilter/xt_multiport.c
@@ -0,0 +1,314 @@
+/* Kernel module to match one of a list of TCP/UDP ports: ports are in
+   the same place so we can treat them as equal. */
+
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/udp.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+
+#include <linux/netfilter/xt_multiport.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
+MODULE_DESCRIPTION("x_tables multiple port match module");
+MODULE_ALIAS("ipt_multiport");
+MODULE_ALIAS("ip6t_multiport");
+
+#if 0
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+/* Returns 1 if the port is matched by the test, 0 otherwise. */
+static inline int
+ports_match(const u_int16_t *portlist, enum xt_multiport_flags flags,
+	    u_int8_t count, u_int16_t src, u_int16_t dst)
+{
+	unsigned int i;
+	for (i = 0; i < count; i++) {
+		if (flags != XT_MULTIPORT_DESTINATION && portlist[i] == src)
+			return 1;
+
+		if (flags != XT_MULTIPORT_SOURCE && portlist[i] == dst)
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Returns 1 if the port is matched by the test, 0 otherwise. */
+static inline int
+ports_match_v1(const struct xt_multiport_v1 *minfo,
+	       u_int16_t src, u_int16_t dst)
+{
+	unsigned int i;
+	u_int16_t s, e;
+
+	for (i = 0; i < minfo->count; i++) {
+		s = minfo->ports[i];
+
+		if (minfo->pflags[i]) {
+			/* range port matching */
+			e = minfo->ports[++i];
+			duprintf("src or dst matches with %d-%d?\n", s, e);
+
+			if (minfo->flags == XT_MULTIPORT_SOURCE
+			    && src >= s && src <= e)
+				return 1 ^ minfo->invert;
+			if (minfo->flags == XT_MULTIPORT_DESTINATION
+			    && dst >= s && dst <= e)
+				return 1 ^ minfo->invert;
+			if (minfo->flags == XT_MULTIPORT_EITHER
+			    && ((dst >= s && dst <= e)
+				|| (src >= s && src <= e)))
+				return 1 ^ minfo->invert;
+		} else {
+			/* exact port matching */
+			duprintf("src or dst matches with %d?\n", s);
+
+			if (minfo->flags == XT_MULTIPORT_SOURCE
+			    && src == s)
+				return 1 ^ minfo->invert;
+			if (minfo->flags == XT_MULTIPORT_DESTINATION
+			    && dst == s)
+				return 1 ^ minfo->invert;
+			if (minfo->flags == XT_MULTIPORT_EITHER
+			    && (src == s || dst == s))
+				return 1 ^ minfo->invert;
+		}
+	}
+
+ 	return minfo->invert;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const struct xt_match *match,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+	u16 _ports[2], *pptr;
+	const struct xt_multiport *multiinfo = matchinfo;
+
+	if (offset)
+		return 0;
+
+	pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
+	if (pptr == NULL) {
+		/* We've been asked to examine this packet, and we
+		 * can't.  Hence, no choice but to drop.
+		 */
+		duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	return ports_match(multiinfo->ports,
+			   multiinfo->flags, multiinfo->count,
+			   ntohs(pptr[0]), ntohs(pptr[1]));
+}
+
+static int
+match_v1(const struct sk_buff *skb,
+	 const struct net_device *in,
+	 const struct net_device *out,
+	 const struct xt_match *match,
+	 const void *matchinfo,
+	 int offset,
+	 unsigned int protoff,
+	 int *hotdrop)
+{
+	u16 _ports[2], *pptr;
+	const struct xt_multiport_v1 *multiinfo = matchinfo;
+
+	if (offset)
+		return 0;
+
+	pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
+	if (pptr == NULL) {
+		/* We've been asked to examine this packet, and we
+		 * can't.  Hence, no choice but to drop.
+		 */
+		duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
+}
+
+static inline int
+check(u_int16_t proto,
+      u_int8_t ip_invflags,
+      u_int8_t match_flags,
+      u_int8_t count)
+{
+	/* Must specify proto == TCP/UDP, no unknown flags or bad count */
+	return (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
+		&& !(ip_invflags & XT_INV_PROTO)
+		&& (match_flags == XT_MULTIPORT_SOURCE
+		    || match_flags == XT_MULTIPORT_DESTINATION
+		    || match_flags == XT_MULTIPORT_EITHER)
+		&& count <= XT_MULTI_PORTS;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const void *info,
+	   const struct xt_match *match,
+	   void *matchinfo,
+	   unsigned int matchsize,
+	   unsigned int hook_mask)
+{
+	const struct ipt_ip *ip = info;
+	const struct xt_multiport *multiinfo = matchinfo;
+
+	return check(ip->proto, ip->invflags, multiinfo->flags,
+		     multiinfo->count);
+}
+
+static int
+checkentry_v1(const char *tablename,
+	      const void *info,
+	      const struct xt_match *match,
+	      void *matchinfo,
+	      unsigned int matchsize,
+	      unsigned int hook_mask)
+{
+	const struct ipt_ip *ip = info;
+	const struct xt_multiport_v1 *multiinfo = matchinfo;
+
+	return check(ip->proto, ip->invflags, multiinfo->flags,
+		     multiinfo->count);
+}
+
+static int
+checkentry6(const char *tablename,
+	    const void *info,
+	    const struct xt_match *match,
+	    void *matchinfo,
+	    unsigned int matchsize,
+	    unsigned int hook_mask)
+{
+	const struct ip6t_ip6 *ip = info;
+	const struct xt_multiport *multiinfo = matchinfo;
+
+	return check(ip->proto, ip->invflags, multiinfo->flags,
+		     multiinfo->count);
+}
+
+static int
+checkentry6_v1(const char *tablename,
+	       const void *info,
+	       const struct xt_match *match,
+	       void *matchinfo,
+	       unsigned int matchsize,
+	       unsigned int hook_mask)
+{
+	const struct ip6t_ip6 *ip = info;
+	const struct xt_multiport_v1 *multiinfo = matchinfo;
+
+	return check(ip->proto, ip->invflags, multiinfo->flags,
+		     multiinfo->count);
+}
+
+static struct xt_match multiport_match = {
+	.name		= "multiport",
+	.revision	= 0,
+	.matchsize	= sizeof(struct xt_multiport),
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.family		= AF_INET,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_match multiport_match_v1 = {
+	.name		= "multiport",
+	.revision	= 1,
+	.matchsize	= sizeof(struct xt_multiport_v1),
+	.match		= &match_v1,
+	.checkentry	= &checkentry_v1,
+	.family		= AF_INET,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_match multiport6_match = {
+	.name		= "multiport",
+	.revision	= 0,
+	.matchsize	= sizeof(struct xt_multiport),
+	.match		= &match,
+	.checkentry	= &checkentry6,
+	.family		= AF_INET6,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_match multiport6_match_v1 = {
+	.name		= "multiport",
+	.revision	= 1,
+	.matchsize	= sizeof(struct xt_multiport_v1),
+	.match		= &match_v1,
+	.checkentry	= &checkentry6_v1,
+	.family		= AF_INET6,
+	.me		= THIS_MODULE,
+};
+
+static int __init xt_multiport_init(void)
+{
+	int ret;
+
+	ret = xt_register_match(&multiport_match);
+	if (ret)
+		goto out;
+
+	ret = xt_register_match(&multiport_match_v1);
+	if (ret)
+		goto out_unreg_multi_v0;
+
+	ret = xt_register_match(&multiport6_match);
+	if (ret)
+		goto out_unreg_multi_v1;
+
+	ret = xt_register_match(&multiport6_match_v1);
+	if (ret)
+		goto out_unreg_multi6_v0;
+
+	return ret;
+
+out_unreg_multi6_v0:
+	xt_unregister_match(&multiport6_match);
+out_unreg_multi_v1:
+	xt_unregister_match(&multiport_match_v1);
+out_unreg_multi_v0:
+	xt_unregister_match(&multiport_match);
+out:
+	return ret;
+}
+
+static void __exit xt_multiport_fini(void)
+{
+	xt_unregister_match(&multiport_match);
+	xt_unregister_match(&multiport_match_v1);
+	xt_unregister_match(&multiport6_match);
+	xt_unregister_match(&multiport6_match_v1);
+}
+
+module_init(xt_multiport_init);
+module_exit(xt_multiport_fini);

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [NETFILTER 02/04]: fix ifdef for connmark support in nf_conntrack_netlink
  2006-03-31  1:09 [NETFILTER 00/04]: Netfilter Update Patrick McHardy
  2006-03-31  1:09 ` [NETFILTER 01/04]: x_tables: unify IPv4/IPv6 multiport match Patrick McHardy
@ 2006-03-31  1:09 ` Patrick McHardy
  2006-03-31  1:09 ` [NETFILTER 03/04]: {ip, nf}_conntrack_netlink: fix expectation notifier unregistration Patrick McHardy
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Patrick McHardy @ 2006-03-31  1:09 UTC (permalink / raw)
  To: davem; +Cc: netfilter-devel, Patrick McHardy

[NETFILTER]: fix ifdef for connmark support in nf_conntrack_netlink

When ctnetlink was ported from ip_conntrack to nf_conntrack two #ifdef's
for connmark support were left unchanged and this code was never
compiled.

Problem noticed by Daniel De Graaf.

Signed-off-by: Martin Josefsson <gandalf@wlug.westbo.se>
Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit ea8b4b5661cae27fae57fc5b992730ec2e44d21c
tree 09e7996acf5faa03f42616b2bc46f90365e9fe12
parent 4d5ee8549d2385d700967246fb8ff6cc1828ceb1
author Martin Josefsson <gandalf@wlug.westbo.se> Wed, 29 Mar 2006 10:08:03 +0200
committer Patrick McHardy <kaber@trash.net> Wed, 29 Mar 2006 10:08:03 +0200

 net/netfilter/nf_conntrack_netlink.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 0e0e9d7..3138ae7 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1022,7 +1022,7 @@ ctnetlink_change_conntrack(struct nf_con
 			return err;
 	}
 
-#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+#if defined(CONFIG_NF_CONNTRACK_MARK)
 	if (cda[CTA_MARK-1])
 		ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
 #endif
@@ -1062,7 +1062,7 @@ ctnetlink_create_conntrack(struct nfattr
 			return err;
 	}
 
-#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+#if defined(CONFIG_NF_CONNTRACK_MARK)
 	if (cda[CTA_MARK-1])
 		ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
 #endif

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [NETFILTER 03/04]: {ip, nf}_conntrack_netlink: fix expectation notifier unregistration
  2006-03-31  1:09 [NETFILTER 00/04]: Netfilter Update Patrick McHardy
  2006-03-31  1:09 ` [NETFILTER 01/04]: x_tables: unify IPv4/IPv6 multiport match Patrick McHardy
  2006-03-31  1:09 ` [NETFILTER 02/04]: fix ifdef for connmark support in nf_conntrack_netlink Patrick McHardy
@ 2006-03-31  1:09 ` Patrick McHardy
  2006-03-31  1:09 ` [NETFILTER 04/04]: iptables 32bit compat layer Patrick McHardy
  2006-03-31 10:15 ` [NETFILTER 00/04]: Netfilter Update David S. Miller
  4 siblings, 0 replies; 8+ messages in thread
From: Patrick McHardy @ 2006-03-31  1:09 UTC (permalink / raw)
  To: davem; +Cc: netfilter-devel, Patrick McHardy

[NETFILTER]: {ip,nf}_conntrack_netlink: fix expectation notifier unregistration

This patch fixes expectation notifier unregistration on module unload to
use ip_conntrack_expect_unregister_notifier(). This bug causes a soft
lockup at the first expectation created after a rmmod ; insmod of this
module.

Should go into -stable as well.

Signed-off-by: Martin Josefsson <gandalf@wlug.westbo.se>
Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit 75032ffac0484237a927b7517fc5926eb9846792
tree fab99dd04115ecd8d3e8f82dbea1b9af613c56d7
parent ea8b4b5661cae27fae57fc5b992730ec2e44d21c
author Martin Josefsson <gandalf@wlug.westbo.se> Wed, 29 Mar 2006 10:08:13 +0200
committer Patrick McHardy <kaber@trash.net> Wed, 29 Mar 2006 10:08:13 +0200

 net/ipv4/netfilter/ip_conntrack_netlink.c |    2 +-
 net/netfilter/nf_conntrack_netlink.c      |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index 9b6e19b..01bd7ca 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -1658,7 +1658,7 @@ static void __exit ctnetlink_exit(void)
 	printk("ctnetlink: unregistering from nfnetlink.\n");
 
 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-	ip_conntrack_unregister_notifier(&ctnl_notifier_exp);
+	ip_conntrack_expect_unregister_notifier(&ctnl_notifier_exp);
 	ip_conntrack_unregister_notifier(&ctnl_notifier);
 #endif
 
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 3138ae7..bd10eb9 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1687,7 +1687,7 @@ static void __exit ctnetlink_exit(void)
 	printk("ctnetlink: unregistering from nfnetlink.\n");
 
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
-	nf_conntrack_unregister_notifier(&ctnl_notifier_exp);
+	nf_conntrack_expect_unregister_notifier(&ctnl_notifier_exp);
 	nf_conntrack_unregister_notifier(&ctnl_notifier);
 #endif
 

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [NETFILTER 04/04]: iptables 32bit compat layer
  2006-03-31  1:09 [NETFILTER 00/04]: Netfilter Update Patrick McHardy
                   ` (2 preceding siblings ...)
  2006-03-31  1:09 ` [NETFILTER 03/04]: {ip, nf}_conntrack_netlink: fix expectation notifier unregistration Patrick McHardy
@ 2006-03-31  1:09 ` Patrick McHardy
  2006-03-31 10:15 ` [NETFILTER 00/04]: Netfilter Update David S. Miller
  4 siblings, 0 replies; 8+ messages in thread
From: Patrick McHardy @ 2006-03-31  1:09 UTC (permalink / raw)
  To: davem; +Cc: netfilter-devel, Patrick McHardy

[NETFILTER]: iptables 32bit compat layer

This patch extends current iptables compatibility layer in order to get
32bit iptables to work on 64bit kernel. Current layer is insufficient due
to alignment checks both in kernel and user space tools.

Patch is for current net-2.6.17 with addition of move of ipt_entry_{match|
target} definitions to xt_entry_{match|target}.

Signed-off-by: Dmitry Mishin <dim@openvz.org>
Acked-off-by: Kirill Korotaev <dev@openvz.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit eceb89a7ceab57caa822175613ea8762a5442ea2
tree 71353d1cee25580de5dbd1812bf2933cd6be14d7
parent 75032ffac0484237a927b7517fc5926eb9846792
author Dmitry Mishin <dim@openvz.org> Thu, 30 Mar 2006 18:00:16 +0200
committer Patrick McHardy <kaber@trash.net> Thu, 30 Mar 2006 18:00:16 +0200

 include/linux/netfilter/x_tables.h       |   67 ++
 include/linux/netfilter_ipv4/ip_tables.h |   18 
 net/compat.c                             |    3 
 net/ipv4/netfilter/ip_tables.c           | 1286 +++++++++++++++++++++++++-----
 net/netfilter/x_tables.c                 |  113 +++
 5 files changed, 1280 insertions(+), 207 deletions(-)

diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 1350e47..f6bdef8 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -142,6 +142,12 @@ struct xt_counters_info
 #define ASSERT_WRITE_LOCK(x)
 #include <linux/netfilter_ipv4/listhelp.h>
 
+#ifdef CONFIG_COMPAT
+#define COMPAT_TO_USER		1
+#define COMPAT_FROM_USER	-1
+#define COMPAT_CALC_SIZE	0
+#endif
+
 struct xt_match
 {
 	struct list_head list;
@@ -175,6 +181,9 @@ struct xt_match
 	void (*destroy)(const struct xt_match *match, void *matchinfo,
 			unsigned int matchinfosize);
 
+	/* Called when userspace align differs from kernel space one */
+	int (*compat)(void *match, void **dstptr, int *size, int convert);
+
 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
 	struct module *me;
 
@@ -220,6 +229,9 @@ struct xt_target
 	void (*destroy)(const struct xt_target *target, void *targinfo,
 			unsigned int targinfosize);
 
+	/* Called when userspace align differs from kernel space one */
+	int (*compat)(void *target, void **dstptr, int *size, int convert);
+
 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
 	struct module *me;
 
@@ -314,6 +326,61 @@ extern void xt_proto_fini(int af);
 extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
 extern void xt_free_table_info(struct xt_table_info *info);
 
+#ifdef CONFIG_COMPAT
+#include <net/compat.h>
+
+struct compat_xt_entry_match
+{
+	union {
+		struct {
+			u_int16_t match_size;
+			char name[XT_FUNCTION_MAXNAMELEN - 1];
+			u_int8_t revision;
+		} user;
+		u_int16_t match_size;
+	} u;
+	unsigned char data[0];
+};
+
+struct compat_xt_entry_target
+{
+	union {
+		struct {
+			u_int16_t target_size;
+			char name[XT_FUNCTION_MAXNAMELEN - 1];
+			u_int8_t revision;
+		} user;
+		u_int16_t target_size;
+	} u;
+	unsigned char data[0];
+};
+
+/* FIXME: this works only on 32 bit tasks
+ * need to change whole approach in order to calculate align as function of
+ * current task alignment */
+
+struct compat_xt_counters
+{
+	u_int32_t cnt[4];
+};
+
+struct compat_xt_counters_info
+{
+	char name[XT_TABLE_MAXNAMELEN];
+	compat_uint_t num_counters;
+	struct compat_xt_counters counters[0];
+};
+
+#define COMPAT_XT_ALIGN(s) (((s) + (__alignof__(struct compat_xt_counters)-1)) \
+		& ~(__alignof__(struct compat_xt_counters)-1))
+
+extern void xt_compat_lock(int af);
+extern void xt_compat_unlock(int af);
+extern int xt_compat_match(void *match, void **dstptr, int *size, int convert);
+extern int xt_compat_target(void *target, void **dstptr, int *size,
+		int convert);
+
+#endif /* CONFIG_COMPAT */
 #endif /* __KERNEL__ */
 
 #endif /* _X_TABLES_H */
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index d5b8c0d..c0dac16 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -316,5 +316,23 @@ extern unsigned int ipt_do_table(struct 
 				 void *userdata);
 
 #define IPT_ALIGN(s) XT_ALIGN(s)
+
+#ifdef CONFIG_COMPAT
+#include <net/compat.h>
+
+struct compat_ipt_entry
+{
+	struct ipt_ip ip;
+	compat_uint_t nfcache;
+	u_int16_t target_offset;
+	u_int16_t next_offset;
+	compat_uint_t comefrom;
+	struct compat_xt_counters counters;
+	unsigned char elems[0];
+};
+
+#define COMPAT_IPT_ALIGN(s) 	COMPAT_XT_ALIGN(s)
+
+#endif /* CONFIG_COMPAT */
 #endif /*__KERNEL__*/
 #endif /* _IPTABLES_H */
diff --git a/net/compat.c b/net/compat.c
index 8fd37cd..d5d69fa 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -476,8 +476,7 @@ asmlinkage long compat_sys_setsockopt(in
 	int err;
 	struct socket *sock;
 
-	/* SO_SET_REPLACE seems to be the same in all levels */
-	if (optname == IPT_SO_SET_REPLACE)
+	if (level == SOL_IPV6 && optname == IPT_SO_SET_REPLACE)
 		return do_netfilter_replace(fd, level, optname,
 					    optval, optlen);
 
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 460fd90..d5b8cdd 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/icmp.h>
 #include <net/ip.h>
+#include <net/compat.h>
 #include <asm/uaccess.h>
 #include <linux/mutex.h>
 #include <linux/proc_fs.h>
@@ -799,17 +800,11 @@ get_counters(const struct xt_table_info 
 	}
 }
 
-static int
-copy_entries_to_user(unsigned int total_size,
-		     struct ipt_table *table,
-		     void __user *userptr)
+static inline struct xt_counters * alloc_counters(struct ipt_table *table)
 {
-	unsigned int off, num, countersize;
-	struct ipt_entry *e;
+	unsigned int countersize;
 	struct xt_counters *counters;
 	struct xt_table_info *private = table->private;
-	int ret = 0;
-	void *loc_cpu_entry;
 
 	/* We need atomic snapshot of counters: rest doesn't change
 	   (other than comefrom, which userspace doesn't care
@@ -818,13 +813,32 @@ copy_entries_to_user(unsigned int total_
 	counters = vmalloc_node(countersize, numa_node_id());
 
 	if (counters == NULL)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	/* First, sum counters... */
 	write_lock_bh(&table->lock);
 	get_counters(private, counters);
 	write_unlock_bh(&table->lock);
 
+	return counters;
+}
+
+static int
+copy_entries_to_user(unsigned int total_size,
+		     struct ipt_table *table,
+		     void __user *userptr)
+{
+	unsigned int off, num;
+	struct ipt_entry *e;
+	struct xt_counters *counters;
+	struct xt_table_info *private = table->private;
+	int ret = 0;
+	void *loc_cpu_entry;
+
+	counters = alloc_counters(table);
+	if (IS_ERR(counters))
+		return PTR_ERR(counters);
+
 	/* choose the copy that is on our node/cpu, ...
 	 * This choice is lazy (because current thread is
 	 * allowed to migrate to another cpu)
@@ -884,44 +898,899 @@ copy_entries_to_user(unsigned int total_
 	return ret;
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_delta {
+	struct compat_delta *next;
+	u_int16_t offset;
+	short delta;
+};
+
+static struct compat_delta *compat_offsets = NULL;
+
+static int compat_add_offset(u_int16_t offset, short delta)
+{
+	struct compat_delta *tmp;
+
+	tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+	tmp->offset = offset;
+	tmp->delta = delta;
+	if (compat_offsets) {
+		tmp->next = compat_offsets->next;
+		compat_offsets->next = tmp;
+	} else {
+		compat_offsets = tmp;
+		tmp->next = NULL;
+	}
+	return 0;
+}
+
+static void compat_flush_offsets(void)
+{
+	struct compat_delta *tmp, *next;
+
+	if (compat_offsets) {
+		for(tmp = compat_offsets; tmp; tmp = next) {
+			next = tmp->next;
+			kfree(tmp);
+		}
+		compat_offsets = NULL;
+	}
+}
+
+static short compat_calc_jump(u_int16_t offset)
+{
+	struct compat_delta *tmp;
+	short delta;
+
+	for(tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next)
+		if (tmp->offset < offset)
+			delta += tmp->delta;
+	return delta;
+}
+
+struct compat_ipt_standard_target
+{
+	struct compat_xt_entry_target target;
+	compat_int_t verdict;
+};
+
+#define IPT_ST_OFFSET	(sizeof(struct ipt_standard_target) - \
+				sizeof(struct compat_ipt_standard_target))
+
+struct compat_ipt_standard
+{
+	struct compat_ipt_entry entry;
+	struct compat_ipt_standard_target target;
+};
+
+static int compat_ipt_standard_fn(void *target,
+		void **dstptr, int *size, int convert)
+{
+	struct compat_ipt_standard_target compat_st, *pcompat_st;
+	struct ipt_standard_target st, *pst;
+	int ret;
+
+	ret = 0;
+	switch (convert) {
+		case COMPAT_TO_USER:
+			pst = (struct ipt_standard_target *)target;
+			memcpy(&compat_st.target, &pst->target,
+					sizeof(struct ipt_entry_target));
+			compat_st.verdict = pst->verdict;
+			if (compat_st.verdict > 0)
+				compat_st.verdict -=
+					compat_calc_jump(compat_st.verdict);
+			compat_st.target.u.user.target_size =
+			sizeof(struct compat_ipt_standard_target);
+			if (__copy_to_user(*dstptr, &compat_st,
+				sizeof(struct compat_ipt_standard_target)))
+				ret = -EFAULT;
+			*size -= IPT_ST_OFFSET;
+			*dstptr += sizeof(struct compat_ipt_standard_target);
+			break;
+		case COMPAT_FROM_USER:
+			pcompat_st =
+				(struct compat_ipt_standard_target *)target;
+			memcpy(&st.target, &pcompat_st->target,
+					sizeof(struct ipt_entry_target));
+			st.verdict = pcompat_st->verdict;
+			if (st.verdict > 0)
+				st.verdict += compat_calc_jump(st.verdict);
+			st.target.u.user.target_size =
+			sizeof(struct ipt_standard_target);
+			memcpy(*dstptr, &st,
+					sizeof(struct ipt_standard_target));
+			*size += IPT_ST_OFFSET;
+			*dstptr += sizeof(struct ipt_standard_target);
+			break;
+		case COMPAT_CALC_SIZE:
+			*size += IPT_ST_OFFSET;
+			break;
+		default:
+			ret = -ENOPROTOOPT;
+			break;
+	}
+	return ret;
+}
+
+static inline int
+compat_calc_match(struct ipt_entry_match *m, int * size)
+{
+	if (m->u.kernel.match->compat)
+		m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
+	else
+		xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
+	return 0;
+}
+
+static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
+		void *base, struct xt_table_info *newinfo)
+{
+	struct ipt_entry_target *t;
+	u_int16_t entry_offset;
+	int off, i, ret;
+
+	off = 0;
+	entry_offset = (void *)e - base;
+	IPT_MATCH_ITERATE(e, compat_calc_match, &off);
+	t = ipt_get_target(e);
+	if (t->u.kernel.target->compat)
+		t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
+	else
+		xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
+	newinfo->size -= off;
+	ret = compat_add_offset(entry_offset, off);
+	if (ret)
+		return ret;
+
+	for (i = 0; i< NF_IP_NUMHOOKS; i++) {
+		if (info->hook_entry[i] && (e < (struct ipt_entry *)
+				(base + info->hook_entry[i])))
+			newinfo->hook_entry[i] -= off;
+		if (info->underflow[i] && (e < (struct ipt_entry *)
+				(base + info->underflow[i])))
+			newinfo->underflow[i] -= off;
+	}
+	return 0;
+}
+
+static int compat_table_info(struct xt_table_info *info,
+		struct xt_table_info *newinfo)
+{
+	void *loc_cpu_entry;
+	int i;
+
+	if (!newinfo || !info)
+		return -EINVAL;
+
+	memset(newinfo, 0, sizeof(struct xt_table_info));
+	newinfo->size = info->size;
+	newinfo->number = info->number;
+	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
+		newinfo->hook_entry[i] = info->hook_entry[i];
+		newinfo->underflow[i] = info->underflow[i];
+	}
+	loc_cpu_entry = info->entries[raw_smp_processor_id()];
+	return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
+			compat_calc_entry, info, loc_cpu_entry, newinfo);
+}
+#endif
+
+static int get_info(void __user *user, int *len, int compat)
+{
+	char name[IPT_TABLE_MAXNAMELEN];
+	struct ipt_table *t;
+	int ret;
+
+	if (*len != sizeof(struct ipt_getinfo)) {
+		duprintf("length %u != %u\n", *len,
+			(unsigned int)sizeof(struct ipt_getinfo));
+		return -EINVAL;
+	}
+
+	if (copy_from_user(name, user, sizeof(name)) != 0)
+		return -EFAULT;
+
+	name[IPT_TABLE_MAXNAMELEN-1] = '\0';
+#ifdef CONFIG_COMPAT
+	if (compat)
+		xt_compat_lock(AF_INET);
+#endif
+	t = try_then_request_module(xt_find_table_lock(AF_INET, name),
+			"iptable_%s", name);
+	if (t && !IS_ERR(t)) {
+		struct ipt_getinfo info;
+		struct xt_table_info *private = t->private;
+
+#ifdef CONFIG_COMPAT
+		if (compat) {
+			struct xt_table_info tmp;
+			ret = compat_table_info(private, &tmp);
+			compat_flush_offsets();
+			private =  &tmp;
+		}
+#endif
+		info.valid_hooks = t->valid_hooks;
+		memcpy(info.hook_entry, private->hook_entry,
+				sizeof(info.hook_entry));
+		memcpy(info.underflow, private->underflow,
+				sizeof(info.underflow));
+		info.num_entries = private->number;
+		info.size = private->size;
+		strcpy(info.name, name);
+
+		if (copy_to_user(user, &info, *len) != 0)
+			ret = -EFAULT;
+		else
+			ret = 0;
+
+		xt_table_unlock(t);
+		module_put(t->me);
+	} else
+		ret = t ? PTR_ERR(t) : -ENOENT;
+#ifdef CONFIG_COMPAT
+	if (compat)
+		xt_compat_unlock(AF_INET);
+#endif
+	return ret;
+}
+
+static int
+get_entries(struct ipt_get_entries __user *uptr, int *len)
+{
+	int ret;
+	struct ipt_get_entries get;
+	struct ipt_table *t;
+
+	if (*len < sizeof(get)) {
+		duprintf("get_entries: %u < %d\n", *len,
+				(unsigned int)sizeof(get));
+		return -EINVAL;
+	}
+	if (copy_from_user(&get, uptr, sizeof(get)) != 0)
+		return -EFAULT;
+	if (*len != sizeof(struct ipt_get_entries) + get.size) {
+		duprintf("get_entries: %u != %u\n", *len,
+				(unsigned int)(sizeof(struct ipt_get_entries) +
+				get.size));
+		return -EINVAL;
+	}
+
+	t = xt_find_table_lock(AF_INET, get.name);
+	if (t && !IS_ERR(t)) {
+		struct xt_table_info *private = t->private;
+		duprintf("t->private->number = %u\n",
+			 private->number);
+		if (get.size == private->size)
+			ret = copy_entries_to_user(private->size,
+						   t, uptr->entrytable);
+		else {
+			duprintf("get_entries: I've got %u not %u!\n",
+				 private->size,
+				 get.size);
+			ret = -EINVAL;
+		}
+		module_put(t->me);
+		xt_table_unlock(t);
+	} else
+		ret = t ? PTR_ERR(t) : -ENOENT;
+
+	return ret;
+}
+
+static int
+__do_replace(const char *name, unsigned int valid_hooks,
+		struct xt_table_info *newinfo, unsigned int num_counters,
+		void __user *counters_ptr)
+{
+	int ret;
+	struct ipt_table *t;
+	struct xt_table_info *oldinfo;
+	struct xt_counters *counters;
+	void *loc_cpu_old_entry;
+
+	ret = 0;
+	counters = vmalloc(num_counters * sizeof(struct xt_counters));
+	if (!counters) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	t = try_then_request_module(xt_find_table_lock(AF_INET, name),
+				    "iptable_%s", name);
+	if (!t || IS_ERR(t)) {
+		ret = t ? PTR_ERR(t) : -ENOENT;
+		goto free_newinfo_counters_untrans;
+	}
+
+	/* You lied! */
+	if (valid_hooks != t->valid_hooks) {
+		duprintf("Valid hook crap: %08X vs %08X\n",
+			 valid_hooks, t->valid_hooks);
+		ret = -EINVAL;
+		goto put_module;
+	}
+
+	oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
+	if (!oldinfo)
+		goto put_module;
+
+	/* Update module usage count based on number of rules */
+	duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+		oldinfo->number, oldinfo->initial_entries, newinfo->number);
+	if ((oldinfo->number > oldinfo->initial_entries) ||
+	    (newinfo->number <= oldinfo->initial_entries))
+		module_put(t->me);
+	if ((oldinfo->number > oldinfo->initial_entries) &&
+	    (newinfo->number <= oldinfo->initial_entries))
+		module_put(t->me);
+
+	/* Get the old counters. */
+	get_counters(oldinfo, counters);
+	/* Decrease module usage counts and free resource */
+	loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
+	IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
+	xt_free_table_info(oldinfo);
+	if (copy_to_user(counters_ptr, counters,
+			 sizeof(struct xt_counters) * num_counters) != 0)
+		ret = -EFAULT;
+	vfree(counters);
+	xt_table_unlock(t);
+	return ret;
+
+ put_module:
+	module_put(t->me);
+	xt_table_unlock(t);
+ free_newinfo_counters_untrans:
+	vfree(counters);
+ out:
+	return ret;
+}
+
+static int
+do_replace(void __user *user, unsigned int len)
+{
+	int ret;
+	struct ipt_replace tmp;
+	struct xt_table_info *newinfo;
+	void *loc_cpu_entry;
+
+	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
+		return -EFAULT;
+
+	/* Hack: Causes ipchains to give correct error msg --RR */
+	if (len != sizeof(tmp) + tmp.size)
+		return -ENOPROTOOPT;
+
+	/* overflow check */
+	if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
+			SMP_CACHE_BYTES)
+		return -ENOMEM;
+	if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
+		return -ENOMEM;
+
+	newinfo = xt_alloc_table_info(tmp.size);
+	if (!newinfo)
+		return -ENOMEM;
+
+	/* choose the copy that is our node/cpu */
+	loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
+	if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
+			   tmp.size) != 0) {
+		ret = -EFAULT;
+		goto free_newinfo;
+	}
+
+	ret = translate_table(tmp.name, tmp.valid_hooks,
+			      newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
+			      tmp.hook_entry, tmp.underflow);
+	if (ret != 0)
+		goto free_newinfo;
+
+	duprintf("ip_tables: Translated table\n");
+
+	ret = __do_replace(tmp.name, tmp.valid_hooks,
+			      newinfo, tmp.num_counters,
+			      tmp.counters);
+	if (ret)
+		goto free_newinfo_untrans;
+	return 0;
+
+ free_newinfo_untrans:
+	IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
+ free_newinfo:
+	xt_free_table_info(newinfo);
+	return ret;
+}
+
+/* We're lazy, and add to the first CPU; overflow works its fey magic
+ * and everything is OK. */
+static inline int
+add_counter_to_entry(struct ipt_entry *e,
+		     const struct xt_counters addme[],
+		     unsigned int *i)
+{
+#if 0
+	duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
+		 *i,
+		 (long unsigned int)e->counters.pcnt,
+		 (long unsigned int)e->counters.bcnt,
+		 (long unsigned int)addme[*i].pcnt,
+		 (long unsigned int)addme[*i].bcnt);
+#endif
+
+	ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
+
+	(*i)++;
+	return 0;
+}
+
+static int
+do_add_counters(void __user *user, unsigned int len, int compat)
+{
+	unsigned int i;
+	struct xt_counters_info tmp;
+	struct xt_counters *paddc;
+	unsigned int num_counters;
+	char *name;
+	int size;
+	void *ptmp;
+	struct ipt_table *t;
+	struct xt_table_info *private;
+	int ret = 0;
+	void *loc_cpu_entry;
+#ifdef CONFIG_COMPAT
+	struct compat_xt_counters_info compat_tmp;
+
+	if (compat) {
+		ptmp = &compat_tmp;
+		size = sizeof(struct compat_xt_counters_info);
+	} else
+#endif
+	{
+		ptmp = &tmp;
+		size = sizeof(struct xt_counters_info);
+	}
+
+	if (copy_from_user(ptmp, user, size) != 0)
+		return -EFAULT;
+
+#ifdef CONFIG_COMPAT
+	if (compat) {
+		num_counters = compat_tmp.num_counters;
+		name = compat_tmp.name;
+	} else
+#endif
+	{
+		num_counters = tmp.num_counters;
+		name = tmp.name;
+	}
+
+	if (len != size + num_counters * sizeof(struct xt_counters))
+		return -EINVAL;
+
+	paddc = vmalloc_node(len - size, numa_node_id());
+	if (!paddc)
+		return -ENOMEM;
+
+	if (copy_from_user(paddc, user + size, len - size) != 0) {
+		ret = -EFAULT;
+		goto free;
+	}
+
+	t = xt_find_table_lock(AF_INET, name);
+	if (!t || IS_ERR(t)) {
+		ret = t ? PTR_ERR(t) : -ENOENT;
+		goto free;
+	}
+
+	write_lock_bh(&t->lock);
+	private = t->private;
+	if (private->number != num_counters) {
+		ret = -EINVAL;
+		goto unlock_up_free;
+	}
+
+	i = 0;
+	/* Choose the copy that is on our node */
+	loc_cpu_entry = private->entries[raw_smp_processor_id()];
+	IPT_ENTRY_ITERATE(loc_cpu_entry,
+			  private->size,
+			  add_counter_to_entry,
+			  paddc,
+			  &i);
+ unlock_up_free:
+	write_unlock_bh(&t->lock);
+	xt_table_unlock(t);
+	module_put(t->me);
+ free:
+	vfree(paddc);
+
+	return ret;
+}
+
+#ifdef CONFIG_COMPAT
+struct compat_ipt_replace {
+	char			name[IPT_TABLE_MAXNAMELEN];
+	u32			valid_hooks;
+	u32			num_entries;
+	u32			size;
+	u32			hook_entry[NF_IP_NUMHOOKS];
+	u32			underflow[NF_IP_NUMHOOKS];
+	u32			num_counters;
+	compat_uptr_t		counters;	/* struct ipt_counters * */
+	struct compat_ipt_entry	entries[0];
+};
+
+static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
+		void __user **dstptr, compat_uint_t *size)
+{
+	if (m->u.kernel.match->compat)
+		return m->u.kernel.match->compat(m, dstptr, size,
+				COMPAT_TO_USER);
+	else
+		return xt_compat_match(m, dstptr, size, COMPAT_TO_USER);
+}
+
+static int compat_copy_entry_to_user(struct ipt_entry *e,
+		void __user **dstptr, compat_uint_t *size)
+{
+	struct ipt_entry_target __user *t;
+	struct compat_ipt_entry __user *ce;
+	u_int16_t target_offset, next_offset;
+	compat_uint_t origsize;
+	int ret;
+
+	ret = -EFAULT;
+	origsize = *size;
+	ce = (struct compat_ipt_entry __user *)*dstptr;
+	if (__copy_to_user(ce, e, sizeof(struct ipt_entry)))
+		goto out;
+
+	*dstptr += sizeof(struct compat_ipt_entry);
+	ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
+	target_offset = e->target_offset - (origsize - *size);
+	if (ret)
+		goto out;
+	t = ipt_get_target(e);
+	if (t->u.kernel.target->compat)
+		ret = t->u.kernel.target->compat(t, dstptr, size,
+				COMPAT_TO_USER);
+	else
+		ret = xt_compat_target(t, dstptr, size, COMPAT_TO_USER);
+	if (ret)
+		goto out;
+	ret = -EFAULT;
+	next_offset = e->next_offset - (origsize - *size);
+	if (__put_user(target_offset, &ce->target_offset))
+		goto out;
+	if (__put_user(next_offset, &ce->next_offset))
+		goto out;
+	return 0;
+out:
+	return ret;
+}
+
+static inline int
+compat_check_calc_match(struct ipt_entry_match *m,
+	    const char *name,
+	    const struct ipt_ip *ip,
+	    unsigned int hookmask,
+	    int *size, int *i)
+{
+	struct ipt_match *match;
+
+	match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
+						   m->u.user.revision),
+					"ipt_%s", m->u.user.name);
+	if (IS_ERR(match) || !match) {
+		duprintf("compat_check_calc_match: `%s' not found\n",
+				m->u.user.name);
+		return match ? PTR_ERR(match) : -ENOENT;
+	}
+	m->u.kernel.match = match;
+
+	if (m->u.kernel.match->compat)
+		m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
+	else
+		xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
+
+	(*i)++;
+	return 0;
+}
+
+static inline int
+check_compat_entry_size_and_hooks(struct ipt_entry *e,
+			   struct xt_table_info *newinfo,
+			   unsigned int *size,
+			   unsigned char *base,
+			   unsigned char *limit,
+			   unsigned int *hook_entries,
+			   unsigned int *underflows,
+			   unsigned int *i,
+			   const char *name)
+{
+	struct ipt_entry_target *t;
+	struct ipt_target *target;
+	u_int16_t entry_offset;
+	int ret, off, h, j;
+
+	duprintf("check_compat_entry_size_and_hooks %p\n", e);
+	if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
+	    || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
+		duprintf("Bad offset %p, limit = %p\n", e, limit);
+		return -EINVAL;
+	}
+
+	if (e->next_offset < sizeof(struct compat_ipt_entry) +
+			sizeof(struct compat_xt_entry_target)) {
+		duprintf("checking: element %p size %u\n",
+			 e, e->next_offset);
+		return -EINVAL;
+	}
+
+	if (!ip_checkentry(&e->ip)) {
+		duprintf("ip_tables: ip check failed %p %s.\n", e, name);
+		return -EINVAL;
+	}
+
+	off = 0;
+	entry_offset = (void *)e - (void *)base;
+	j = 0;
+	ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
+			e->comefrom, &off, &j);
+	if (ret != 0)
+		goto out;
+
+	t = ipt_get_target(e);
+	target = try_then_request_module(xt_find_target(AF_INET,
+						     t->u.user.name,
+						     t->u.user.revision),
+					 "ipt_%s", t->u.user.name);
+	if (IS_ERR(target) || !target) {
+		duprintf("check_entry: `%s' not found\n", t->u.user.name);
+		ret = target ? PTR_ERR(target) : -ENOENT;
+		goto out;
+	}
+	t->u.kernel.target = target;
+
+	if (t->u.kernel.target->compat)
+		t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
+	else
+		xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
+	*size += off;
+	ret = compat_add_offset(entry_offset, off);
+	if (ret)
+		goto out;
+
+	/* Check hooks & underflows */
+	for (h = 0; h < NF_IP_NUMHOOKS; h++) {
+		if ((unsigned char *)e - base == hook_entries[h])
+			newinfo->hook_entry[h] = hook_entries[h];
+		if ((unsigned char *)e - base == underflows[h])
+			newinfo->underflow[h] = underflows[h];
+	}
+
+	/* Clear counters and comefrom */
+	e->counters = ((struct ipt_counters) { 0, 0 });
+	e->comefrom = 0;
+
+	(*i)++;
+	return 0;
+out:
+	IPT_MATCH_ITERATE(e, cleanup_match, &j);
+	return ret;
+}
+
+static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
+	void **dstptr, compat_uint_t *size, const char *name,
+	const struct ipt_ip *ip, unsigned int hookmask)
+{
+	struct ipt_entry_match *dm;
+	struct ipt_match *match;
+	int ret;
+
+	dm = (struct ipt_entry_match *)*dstptr;
+	match = m->u.kernel.match;
+	if (match->compat)
+		match->compat(m, dstptr, size, COMPAT_FROM_USER);
+	else
+		xt_compat_match(m, dstptr, size, COMPAT_FROM_USER);
+
+	ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
+			     name, hookmask, ip->proto,
+			     ip->invflags & IPT_INV_PROTO);
+	if (ret)
+		return ret;
+
+	if (m->u.kernel.match->checkentry
+	    && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
+					      dm->u.match_size - sizeof(*dm),
+					      hookmask)) {
+		duprintf("ip_tables: check failed for `%s'.\n",
+			 m->u.kernel.match->name);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
+	unsigned int *size, const char *name,
+	struct xt_table_info *newinfo, unsigned char *base)
+{
+	struct ipt_entry_target *t;
+	struct ipt_target *target;
+	struct ipt_entry *de;
+	unsigned int origsize;
+	int ret, h;
+
+	ret = 0;
+	origsize = *size;
+	de = (struct ipt_entry *)*dstptr;
+	memcpy(de, e, sizeof(struct ipt_entry));
+
+	*dstptr += sizeof(struct compat_ipt_entry);
+	ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
+			name, &de->ip, de->comefrom);
+	if (ret)
+		goto out;
+	de->target_offset = e->target_offset - (origsize - *size);
+	t = ipt_get_target(e);
+	target = t->u.kernel.target;
+	if (target->compat)
+		target->compat(t, dstptr, size, COMPAT_FROM_USER);
+	else
+		xt_compat_target(t, dstptr, size, COMPAT_FROM_USER);
+
+	de->next_offset = e->next_offset - (origsize - *size);
+	for (h = 0; h < NF_IP_NUMHOOKS; h++) {
+		if ((unsigned char *)de - base < newinfo->hook_entry[h])
+			newinfo->hook_entry[h] -= origsize - *size;
+		if ((unsigned char *)de - base < newinfo->underflow[h])
+			newinfo->underflow[h] -= origsize - *size;
+	}
+
+	t = ipt_get_target(de);
+	target = t->u.kernel.target;
+	ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
+			      name, e->comefrom, e->ip.proto,
+			      e->ip.invflags & IPT_INV_PROTO);
+	if (ret)
+		goto out;
+
+	ret = -EINVAL;
+	if (t->u.kernel.target == &ipt_standard_target) {
+		if (!standard_check(t, *size))
+			goto out;
+	} else if (t->u.kernel.target->checkentry
+		   && !t->u.kernel.target->checkentry(name, de, target,
+				t->data, t->u.target_size - sizeof(*t),
+				de->comefrom)) {
+		duprintf("ip_tables: compat: check failed for `%s'.\n",
+			 t->u.kernel.target->name);
+		goto out;
+	}
+	ret = 0;
+out:
+	return ret;
+}
+
 static int
-get_entries(const struct ipt_get_entries *entries,
-	    struct ipt_get_entries __user *uptr)
+translate_compat_table(const char *name,
+		unsigned int valid_hooks,
+		struct xt_table_info **pinfo,
+		void **pentry0,
+		unsigned int total_size,
+		unsigned int number,
+		unsigned int *hook_entries,
+		unsigned int *underflows)
 {
+	unsigned int i;
+	struct xt_table_info *newinfo, *info;
+	void *pos, *entry0, *entry1;
+	unsigned int size;
 	int ret;
-	struct ipt_table *t;
 
-	t = xt_find_table_lock(AF_INET, entries->name);
-	if (t && !IS_ERR(t)) {
-		struct xt_table_info *private = t->private;
-		duprintf("t->private->number = %u\n",
-			 private->number);
-		if (entries->size == private->size)
-			ret = copy_entries_to_user(private->size,
-						   t, uptr->entrytable);
-		else {
-			duprintf("get_entries: I've got %u not %u!\n",
-				 private->size,
-				 entries->size);
-			ret = -EINVAL;
+	info = *pinfo;
+	entry0 = *pentry0;
+	size = total_size;
+	info->number = number;
+
+	/* Init all hooks to impossible value. */
+	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
+		info->hook_entry[i] = 0xFFFFFFFF;
+		info->underflow[i] = 0xFFFFFFFF;
+	}
+
+	duprintf("translate_compat_table: size %u\n", info->size);
+	i = 0;
+	xt_compat_lock(AF_INET);
+	/* Walk through entries, checking offsets. */
+	ret = IPT_ENTRY_ITERATE(entry0, total_size,
+				check_compat_entry_size_and_hooks,
+				info, &size, entry0,
+				entry0 + total_size,
+				hook_entries, underflows, &i, name);
+	if (ret != 0)
+		goto out_unlock;
+
+	ret = -EINVAL;
+	if (i != number) {
+		duprintf("translate_compat_table: %u not %u entries\n",
+			 i, number);
+		goto out_unlock;
+	}
+
+	/* Check hooks all assigned */
+	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
+		/* Only hooks which are valid */
+		if (!(valid_hooks & (1 << i)))
+			continue;
+		if (info->hook_entry[i] == 0xFFFFFFFF) {
+			duprintf("Invalid hook entry %u %u\n",
+				 i, hook_entries[i]);
+			goto out_unlock;
 		}
-		module_put(t->me);
-		xt_table_unlock(t);
-	} else
-		ret = t ? PTR_ERR(t) : -ENOENT;
+		if (info->underflow[i] == 0xFFFFFFFF) {
+			duprintf("Invalid underflow %u %u\n",
+				 i, underflows[i]);
+			goto out_unlock;
+		}
+	}
+
+	ret = -ENOMEM;
+	newinfo = xt_alloc_table_info(size);
+	if (!newinfo)
+		goto out_unlock;
+
+	newinfo->number = number;
+	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
+		newinfo->hook_entry[i] = info->hook_entry[i];
+		newinfo->underflow[i] = info->underflow[i];
+	}
+	entry1 = newinfo->entries[raw_smp_processor_id()];
+	pos = entry1;
+	size =  total_size;
+	ret = IPT_ENTRY_ITERATE(entry0, total_size,
+			compat_copy_entry_from_user, &pos, &size,
+			name, newinfo, entry1);
+	compat_flush_offsets();
+	xt_compat_unlock(AF_INET);
+	if (ret)
+		goto free_newinfo;
+
+	ret = -ELOOP;
+	if (!mark_source_chains(newinfo, valid_hooks, entry1))
+		goto free_newinfo;
+
+	/* And one copy for every other CPU */
+	for_each_cpu(i)
+		if (newinfo->entries[i] && newinfo->entries[i] != entry1)
+			memcpy(newinfo->entries[i], entry1, newinfo->size);
+
+	*pinfo = newinfo;
+	*pentry0 = entry1;
+	xt_free_table_info(info);
+	return 0;
 
+free_newinfo:
+	xt_free_table_info(newinfo);
+out:
 	return ret;
+out_unlock:
+	xt_compat_unlock(AF_INET);
+	goto out;
 }
 
 static int
-do_replace(void __user *user, unsigned int len)
+compat_do_replace(void __user *user, unsigned int len)
 {
 	int ret;
-	struct ipt_replace tmp;
-	struct ipt_table *t;
-	struct xt_table_info *newinfo, *oldinfo;
-	struct xt_counters *counters;
-	void *loc_cpu_entry, *loc_cpu_old_entry;
+	struct compat_ipt_replace tmp;
+	struct xt_table_info *newinfo;
+	void *loc_cpu_entry;
 
 	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
 		return -EFAULT;
@@ -949,151 +1818,201 @@ do_replace(void __user *user, unsigned i
 		goto free_newinfo;
 	}
 
-	counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
-	if (!counters) {
-		ret = -ENOMEM;
+	ret = translate_compat_table(tmp.name, tmp.valid_hooks,
+			      &newinfo, &loc_cpu_entry, tmp.size,
+			      tmp.num_entries, tmp.hook_entry, tmp.underflow);
+	if (ret != 0)
 		goto free_newinfo;
-	}
 
-	ret = translate_table(tmp.name, tmp.valid_hooks,
-			      newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
-			      tmp.hook_entry, tmp.underflow);
-	if (ret != 0)
-		goto free_newinfo_counters;
+	duprintf("compat_do_replace: Translated table\n");
 
-	duprintf("ip_tables: Translated table\n");
+	ret = __do_replace(tmp.name, tmp.valid_hooks,
+			      newinfo, tmp.num_counters,
+			      compat_ptr(tmp.counters));
+	if (ret)
+		goto free_newinfo_untrans;
+	return 0;
 
-	t = try_then_request_module(xt_find_table_lock(AF_INET, tmp.name),
-				    "iptable_%s", tmp.name);
-	if (!t || IS_ERR(t)) {
-		ret = t ? PTR_ERR(t) : -ENOENT;
-		goto free_newinfo_counters_untrans;
-	}
+ free_newinfo_untrans:
+	IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
+ free_newinfo:
+	xt_free_table_info(newinfo);
+	return ret;
+}
 
-	/* You lied! */
-	if (tmp.valid_hooks != t->valid_hooks) {
-		duprintf("Valid hook crap: %08X vs %08X\n",
-			 tmp.valid_hooks, t->valid_hooks);
-		ret = -EINVAL;
-		goto put_module;
-	}
+static int
+compat_do_ipt_set_ctl(struct sock *sk,	int cmd, void __user *user,
+		unsigned int len)
+{
+	int ret;
 
-	oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
-	if (!oldinfo)
-		goto put_module;
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
 
-	/* Update module usage count based on number of rules */
-	duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
-		oldinfo->number, oldinfo->initial_entries, newinfo->number);
-	if ((oldinfo->number > oldinfo->initial_entries) || 
-	    (newinfo->number <= oldinfo->initial_entries)) 
-		module_put(t->me);
-	if ((oldinfo->number > oldinfo->initial_entries) &&
-	    (newinfo->number <= oldinfo->initial_entries))
-		module_put(t->me);
+	switch (cmd) {
+	case IPT_SO_SET_REPLACE:
+		ret = compat_do_replace(user, len);
+		break;
 
-	/* Get the old counters. */
-	get_counters(oldinfo, counters);
-	/* Decrease module usage counts and free resource */
-	loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
-	IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
-	xt_free_table_info(oldinfo);
-	if (copy_to_user(tmp.counters, counters,
-			 sizeof(struct xt_counters) * tmp.num_counters) != 0)
-		ret = -EFAULT;
-	vfree(counters);
-	xt_table_unlock(t);
-	return ret;
+	case IPT_SO_SET_ADD_COUNTERS:
+		ret = do_add_counters(user, len, 1);
+		break;
+
+	default:
+		duprintf("do_ipt_set_ctl:  unknown request %i\n", cmd);
+		ret = -EINVAL;
+	}
 
- put_module:
-	module_put(t->me);
-	xt_table_unlock(t);
- free_newinfo_counters_untrans:
-	IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
- free_newinfo_counters:
-	vfree(counters);
- free_newinfo:
-	xt_free_table_info(newinfo);
 	return ret;
 }
 
-/* We're lazy, and add to the first CPU; overflow works its fey magic
- * and everything is OK. */
-static inline int
-add_counter_to_entry(struct ipt_entry *e,
-		     const struct xt_counters addme[],
-		     unsigned int *i)
+struct compat_ipt_get_entries
 {
-#if 0
-	duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
-		 *i,
-		 (long unsigned int)e->counters.pcnt,
-		 (long unsigned int)e->counters.bcnt,
-		 (long unsigned int)addme[*i].pcnt,
-		 (long unsigned int)addme[*i].bcnt);
-#endif
+	char name[IPT_TABLE_MAXNAMELEN];
+	compat_uint_t size;
+	struct compat_ipt_entry entrytable[0];
+};
 
-	ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
+static int compat_copy_entries_to_user(unsigned int total_size,
+		     struct ipt_table *table, void __user *userptr)
+{
+	unsigned int off, num;
+	struct compat_ipt_entry e;
+	struct xt_counters *counters;
+	struct xt_table_info *private = table->private;
+	void __user *pos;
+	unsigned int size;
+	int ret = 0;
+	void *loc_cpu_entry;
 
-	(*i)++;
-	return 0;
+	counters = alloc_counters(table);
+	if (IS_ERR(counters))
+		return PTR_ERR(counters);
+
+	/* choose the copy that is on our node/cpu, ...
+	 * This choice is lazy (because current thread is
+	 * allowed to migrate to another cpu)
+	 */
+	loc_cpu_entry = private->entries[raw_smp_processor_id()];
+	pos = userptr;
+	size = total_size;
+	ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
+			compat_copy_entry_to_user, &pos, &size);
+	if (ret)
+		goto free_counters;
+
+	/* ... then go back and fix counters and names */
+	for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
+		unsigned int i;
+		struct ipt_entry_match m;
+		struct ipt_entry_target t;
+
+		ret = -EFAULT;
+		if (copy_from_user(&e, userptr + off,
+					sizeof(struct compat_ipt_entry)))
+			goto free_counters;
+		if (copy_to_user(userptr + off +
+			offsetof(struct compat_ipt_entry, counters),
+			 &counters[num], sizeof(counters[num])))
+			goto free_counters;
+
+		for (i = sizeof(struct compat_ipt_entry);
+				i < e.target_offset; i += m.u.match_size) {
+			if (copy_from_user(&m, userptr + off + i,
+					sizeof(struct ipt_entry_match)))
+				goto free_counters;
+			if (copy_to_user(userptr + off + i +
+				offsetof(struct ipt_entry_match, u.user.name),
+				m.u.kernel.match->name,
+				strlen(m.u.kernel.match->name) + 1))
+				goto free_counters;
+		}
+
+		if (copy_from_user(&t, userptr + off + e.target_offset,
+					sizeof(struct ipt_entry_target)))
+			goto free_counters;
+		if (copy_to_user(userptr + off + e.target_offset +
+			offsetof(struct ipt_entry_target, u.user.name),
+			t.u.kernel.target->name,
+			strlen(t.u.kernel.target->name) + 1))
+			goto free_counters;
+	}
+	ret = 0;
+free_counters:
+	vfree(counters);
+	return ret;
 }
 
 static int
-do_add_counters(void __user *user, unsigned int len)
+compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
 {
-	unsigned int i;
-	struct xt_counters_info tmp, *paddc;
+	int ret;
+	struct compat_ipt_get_entries get;
 	struct ipt_table *t;
-	struct xt_table_info *private;
-	int ret = 0;
-	void *loc_cpu_entry;
 
-	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
-		return -EFAULT;
 
-	if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
+	if (*len < sizeof(get)) {
+		duprintf("compat_get_entries: %u < %u\n",
+				*len, (unsigned int)sizeof(get));
 		return -EINVAL;
+	}
 
-	paddc = vmalloc_node(len, numa_node_id());
-	if (!paddc)
-		return -ENOMEM;
+	if (copy_from_user(&get, uptr, sizeof(get)) != 0)
+		return -EFAULT;
 
-	if (copy_from_user(paddc, user, len) != 0) {
-		ret = -EFAULT;
-		goto free;
+	if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
+		duprintf("compat_get_entries: %u != %u\n", *len,
+			(unsigned int)(sizeof(struct compat_ipt_get_entries) +
+			get.size));
+		return -EINVAL;
 	}
 
-	t = xt_find_table_lock(AF_INET, tmp.name);
-	if (!t || IS_ERR(t)) {
+	xt_compat_lock(AF_INET);
+	t = xt_find_table_lock(AF_INET, get.name);
+	if (t && !IS_ERR(t)) {
+		struct xt_table_info *private = t->private;
+		struct xt_table_info info;
+		duprintf("t->private->number = %u\n",
+			 private->number);
+		ret = compat_table_info(private, &info);
+		if (!ret && get.size == info.size) {
+			ret = compat_copy_entries_to_user(private->size,
+						   t, uptr->entrytable);
+		} else if (!ret) {
+			duprintf("compat_get_entries: I've got %u not %u!\n",
+				 private->size,
+				 get.size);
+			ret = -EINVAL;
+		}
+		compat_flush_offsets();
+		module_put(t->me);
+		xt_table_unlock(t);
+	} else
 		ret = t ? PTR_ERR(t) : -ENOENT;
-		goto free;
-	}
 
-	write_lock_bh(&t->lock);
-	private = t->private;
-	if (private->number != paddc->num_counters) {
-		ret = -EINVAL;
-		goto unlock_up_free;
-	}
+	xt_compat_unlock(AF_INET);
+	return ret;
+}
 
-	i = 0;
-	/* Choose the copy that is on our node */
-	loc_cpu_entry = private->entries[raw_smp_processor_id()];
-	IPT_ENTRY_ITERATE(loc_cpu_entry,
-			  private->size,
-			  add_counter_to_entry,
-			  paddc->counters,
-			  &i);
- unlock_up_free:
-	write_unlock_bh(&t->lock);
-	xt_table_unlock(t);
-	module_put(t->me);
- free:
-	vfree(paddc);
+static int
+compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+{
+	int ret;
 
+	switch (cmd) {
+	case IPT_SO_GET_INFO:
+		ret = get_info(user, len, 1);
+		break;
+	case IPT_SO_GET_ENTRIES:
+		ret = compat_get_entries(user, len);
+		break;
+	default:
+		duprintf("compat_do_ipt_get_ctl: unknown request %i\n", cmd);
+		ret = -EINVAL;
+	}
 	return ret;
 }
+#endif
 
 static int
 do_ipt_set_ctl(struct sock *sk,	int cmd, void __user *user, unsigned int len)
@@ -1109,7 +2028,7 @@ do_ipt_set_ctl(struct sock *sk,	int cmd,
 		break;
 
 	case IPT_SO_SET_ADD_COUNTERS:
-		ret = do_add_counters(user, len);
+		ret = do_add_counters(user, len, 0);
 		break;
 
 	default:
@@ -1129,65 +2048,13 @@ do_ipt_get_ctl(struct sock *sk, int cmd,
 		return -EPERM;
 
 	switch (cmd) {
-	case IPT_SO_GET_INFO: {
-		char name[IPT_TABLE_MAXNAMELEN];
-		struct ipt_table *t;
-
-		if (*len != sizeof(struct ipt_getinfo)) {
-			duprintf("length %u != %u\n", *len,
-				 sizeof(struct ipt_getinfo));
-			ret = -EINVAL;
-			break;
-		}
-
-		if (copy_from_user(name, user, sizeof(name)) != 0) {
-			ret = -EFAULT;
-			break;
-		}
-		name[IPT_TABLE_MAXNAMELEN-1] = '\0';
-
-		t = try_then_request_module(xt_find_table_lock(AF_INET, name),
-					    "iptable_%s", name);
-		if (t && !IS_ERR(t)) {
-			struct ipt_getinfo info;
-			struct xt_table_info *private = t->private;
-
-			info.valid_hooks = t->valid_hooks;
-			memcpy(info.hook_entry, private->hook_entry,
-			       sizeof(info.hook_entry));
-			memcpy(info.underflow, private->underflow,
-			       sizeof(info.underflow));
-			info.num_entries = private->number;
-			info.size = private->size;
-			memcpy(info.name, name, sizeof(info.name));
-
-			if (copy_to_user(user, &info, *len) != 0)
-				ret = -EFAULT;
-			else
-				ret = 0;
-			xt_table_unlock(t);
-			module_put(t->me);
-		} else
-			ret = t ? PTR_ERR(t) : -ENOENT;
-	}
-	break;
-
-	case IPT_SO_GET_ENTRIES: {
-		struct ipt_get_entries get;
+	case IPT_SO_GET_INFO:
+		ret = get_info(user, len, 0);
+		break;
 
-		if (*len < sizeof(get)) {
-			duprintf("get_entries: %u < %u\n", *len, sizeof(get));
-			ret = -EINVAL;
-		} else if (copy_from_user(&get, user, sizeof(get)) != 0) {
-			ret = -EFAULT;
-		} else if (*len != sizeof(struct ipt_get_entries) + get.size) {
-			duprintf("get_entries: %u != %u\n", *len,
-				 sizeof(struct ipt_get_entries) + get.size);
-			ret = -EINVAL;
-		} else
-			ret = get_entries(&get, user);
+	case IPT_SO_GET_ENTRIES:
+		ret = get_entries(user, len);
 		break;
-	}
 
 	case IPT_SO_GET_REVISION_MATCH:
 	case IPT_SO_GET_REVISION_TARGET: {
@@ -1336,6 +2203,9 @@ static struct ipt_target ipt_standard_ta
 	.name		= IPT_STANDARD_TARGET,
 	.targetsize	= sizeof(int),
 	.family		= AF_INET,
+#ifdef CONFIG_COMPAT
+	.compat		= &compat_ipt_standard_fn,
+#endif
 };
 
 static struct ipt_target ipt_error_target = {
@@ -1350,9 +2220,15 @@ static struct nf_sockopt_ops ipt_sockopt
 	.set_optmin	= IPT_BASE_CTL,
 	.set_optmax	= IPT_SO_SET_MAX+1,
 	.set		= do_ipt_set_ctl,
+#ifdef CONFIG_COMPAT
+	.compat_set	= compat_do_ipt_set_ctl,
+#endif
 	.get_optmin	= IPT_BASE_CTL,
 	.get_optmax	= IPT_SO_GET_MAX+1,
 	.get		= do_ipt_get_ctl,
+#ifdef CONFIG_COMPAT
+	.compat_get	= compat_do_ipt_get_ctl,
+#endif
 };
 
 static struct ipt_match icmp_matchstruct = {
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index a657ab5..feb8a9e 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -38,6 +38,7 @@ struct xt_af {
 	struct list_head match;
 	struct list_head target;
 	struct list_head tables;
+	struct mutex compat_mutex;
 };
 
 static struct xt_af *xt;
@@ -272,6 +273,54 @@ int xt_check_match(const struct xt_match
 }
 EXPORT_SYMBOL_GPL(xt_check_match);
 
+#ifdef CONFIG_COMPAT
+int xt_compat_match(void *match, void **dstptr, int *size, int convert)
+{
+	struct xt_match *m;
+	struct compat_xt_entry_match *pcompat_m;
+	struct xt_entry_match *pm;
+	u_int16_t msize;
+	int off, ret;
+
+	ret = 0;
+	m = ((struct xt_entry_match *)match)->u.kernel.match;
+	off = XT_ALIGN(m->matchsize) - COMPAT_XT_ALIGN(m->matchsize);
+	switch (convert) {
+		case COMPAT_TO_USER:
+			pm = (struct xt_entry_match *)match;
+			msize = pm->u.user.match_size;
+			if (__copy_to_user(*dstptr, pm, msize)) {
+				ret = -EFAULT;
+				break;
+			}
+			msize -= off;
+			if (put_user(msize, (u_int16_t *)*dstptr))
+				ret = -EFAULT;
+			*size -= off;
+			*dstptr += msize;
+			break;
+		case COMPAT_FROM_USER:
+			pcompat_m = (struct compat_xt_entry_match *)match;
+			pm = (struct xt_entry_match *)*dstptr;
+			msize = pcompat_m->u.user.match_size;
+			memcpy(pm, pcompat_m, msize);
+			msize += off;
+			pm->u.user.match_size = msize;
+			*size += off;
+			*dstptr += msize;
+			break;
+		case COMPAT_CALC_SIZE:
+			*size += off;
+			break;
+		default:
+			ret = -ENOPROTOOPT;
+			break;
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xt_compat_match);
+#endif
+
 int xt_check_target(const struct xt_target *target, unsigned short family,
 		    unsigned int size, const char *table, unsigned int hook_mask,
 		    unsigned short proto, int inv_proto)
@@ -301,6 +350,54 @@ int xt_check_target(const struct xt_targ
 }
 EXPORT_SYMBOL_GPL(xt_check_target);
 
+#ifdef CONFIG_COMPAT
+int xt_compat_target(void *target, void **dstptr, int *size, int convert)
+{
+	struct xt_target *t;
+	struct compat_xt_entry_target *pcompat;
+	struct xt_entry_target *pt;
+	u_int16_t tsize;
+	int off, ret;
+
+	ret = 0;
+	t = ((struct xt_entry_target *)target)->u.kernel.target;
+	off = XT_ALIGN(t->targetsize) - COMPAT_XT_ALIGN(t->targetsize);
+	switch (convert) {
+		case COMPAT_TO_USER:
+			pt = (struct xt_entry_target *)target;
+			tsize = pt->u.user.target_size;
+			if (__copy_to_user(*dstptr, pt, tsize)) {
+				ret = -EFAULT;
+				break;
+			}
+			tsize -= off;
+			if (put_user(tsize, (u_int16_t *)*dstptr))
+				ret = -EFAULT;
+			*size -= off;
+			*dstptr += tsize;
+			break;
+		case COMPAT_FROM_USER:
+			pcompat = (struct compat_xt_entry_target *)target;
+			pt = (struct xt_entry_target *)*dstptr;
+			tsize = pcompat->u.user.target_size;
+			memcpy(pt, pcompat, tsize);
+			tsize += off;
+			pt->u.user.target_size = tsize;
+			*size += off;
+			*dstptr += tsize;
+			break;
+		case COMPAT_CALC_SIZE:
+			*size += off;
+			break;
+		default:
+			ret = -ENOPROTOOPT;
+			break;
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xt_compat_target);
+#endif
+
 struct xt_table_info *xt_alloc_table_info(unsigned int size)
 {
 	struct xt_table_info *newinfo;
@@ -371,6 +468,19 @@ void xt_table_unlock(struct xt_table *ta
 }
 EXPORT_SYMBOL_GPL(xt_table_unlock);
 
+#ifdef CONFIG_COMPAT
+void xt_compat_lock(int af)
+{
+	mutex_lock(&xt[af].compat_mutex);
+}
+EXPORT_SYMBOL_GPL(xt_compat_lock);
+
+void xt_compat_unlock(int af)
+{
+	mutex_unlock(&xt[af].compat_mutex);
+}
+EXPORT_SYMBOL_GPL(xt_compat_unlock);
+#endif
 
 struct xt_table_info *
 xt_replace_table(struct xt_table *table,
@@ -671,6 +781,9 @@ static int __init xt_init(void)
 
 	for (i = 0; i < NPROTO; i++) {
 		mutex_init(&xt[i].mutex);
+#ifdef CONFIG_COMPAT
+		mutex_init(&xt[i].compat_mutex);
+#endif
 		INIT_LIST_HEAD(&xt[i].target);
 		INIT_LIST_HEAD(&xt[i].match);
 		INIT_LIST_HEAD(&xt[i].tables);

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [NETFILTER 00/04]: Netfilter Update
  2006-03-31  1:09 [NETFILTER 00/04]: Netfilter Update Patrick McHardy
                   ` (3 preceding siblings ...)
  2006-03-31  1:09 ` [NETFILTER 04/04]: iptables 32bit compat layer Patrick McHardy
@ 2006-03-31 10:15 ` David S. Miller
  2006-03-31 10:28   ` Patrick McHardy
  4 siblings, 1 reply; 8+ messages in thread
From: David S. Miller @ 2006-03-31 10:15 UTC (permalink / raw)
  To: kaber; +Cc: netfilter-devel

From: Patrick McHardy <kaber@trash.net>
Date: Fri, 31 Mar 2006 03:09:05 +0200 (MEST)

> Yasuyuki Kozakai:
>       [NETFILTER]: x_tables: unify IPv4/IPv6 multiport match

This first patch didn't apply, so I'm going to pass on all of these
until you figure out what's wrong here.

The problem is the net/ipv6/netfilter/Makefile hunk.

@@ -10,7 +10,6 @@ obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) +=
 obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
-obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o

in my current tree the ip6t_ah.o line instead reads as:

obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o

It seems something is wrong with the tree you generated these
patches against.

Please resubmit once you've fixed this, thanks.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [NETFILTER 00/04]: Netfilter Update
  2006-03-31 10:15 ` [NETFILTER 00/04]: Netfilter Update David S. Miller
@ 2006-03-31 10:28   ` Patrick McHardy
  2006-03-31 10:32     ` David S. Miller
  0 siblings, 1 reply; 8+ messages in thread
From: Patrick McHardy @ 2006-03-31 10:28 UTC (permalink / raw)
  To: David S. Miller; +Cc: netfilter-devel

[-- Attachment #1: Type: text/plain, Size: 1122 bytes --]

David S. Miller wrote:
> From: Patrick McHardy <kaber@trash.net>
> Date: Fri, 31 Mar 2006 03:09:05 +0200 (MEST)
> 
> 
>>Yasuyuki Kozakai:
>>      [NETFILTER]: x_tables: unify IPv4/IPv6 multiport match
> 
> 
> This first patch didn't apply, so I'm going to pass on all of these
> until you figure out what's wrong here.
> 
> The problem is the net/ipv6/netfilter/Makefile hunk.
> 
> @@ -10,7 +10,6 @@ obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) +=
>  obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
>  obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
>  obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
> -obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
> 
> in my current tree the ip6t_ah.o line instead reads as:
> 
> obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
> 
> It seems something is wrong with the tree you generated these
> patches against.
> 
> Please resubmit once you've fixed this, thanks.

Sorry, I accidentally missed the first patch. I've attached it to
this mail, with it the patches apply cleanly against the current tree.
If you want me to resubmit the entire set anyway please say so.
Thanks.


[-- Attachment #2: 01.diff --]
[-- Type: text/plain, Size: 16830 bytes --]

[NETFILTER]: x_tables: unify IPv4/IPv6 esp match

This unifies ipt_esp and ip6t_esp to xt_esp. Please note that now
a user program needs to specify IPPROTO_ESP as protocol to use esp match
with IPv6. This means that ip6tables requires '-p esp' like iptables.

Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit 6b0b3ab9f047358723d8b3116b71318f64088a1a
tree 0e8d7dcd24ee91e251d8451a7dec51eed50ea338
parent 91b9a1a505eb4b947318aaba4aed65fec9ccc88b
author Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp> Wed, 29 Mar 2006 10:05:53 +0200
committer Patrick McHardy <kaber@trash.net> Wed, 29 Mar 2006 10:05:53 +0200

 include/linux/netfilter/xt_esp.h        |   14 +++
 include/linux/netfilter_ipv4/ipt_esp.h  |   14 +--
 include/linux/netfilter_ipv6/ip6t_esp.h |   12 +--
 net/ipv4/netfilter/Kconfig              |    8 +-
 net/ipv4/netfilter/Makefile             |    2 
 net/ipv4/netfilter/ipt_esp.c            |  111 -------------------------
 net/ipv6/netfilter/Kconfig              |    6 +
 net/ipv6/netfilter/Makefile             |    2 
 net/ipv6/netfilter/ip6t_esp.c           |  115 --------------------------
 net/netfilter/Kconfig                   |    9 ++
 net/netfilter/Makefile                  |    1 
 net/netfilter/xt_esp.c                  |  136 +++++++++++++++++++++++++++++++
 12 files changed, 177 insertions(+), 253 deletions(-)

diff --git a/include/linux/netfilter/xt_esp.h b/include/linux/netfilter/xt_esp.h
new file mode 100644
index 0000000..9380fb1
--- /dev/null
+++ b/include/linux/netfilter/xt_esp.h
@@ -0,0 +1,14 @@
+#ifndef _XT_ESP_H
+#define _XT_ESP_H
+
+struct xt_esp
+{
+	u_int32_t spis[2];	/* Security Parameter Index */
+	u_int8_t  invflags;	/* Inverse flags */
+};
+
+/* Values for "invflags" field in struct xt_esp. */
+#define XT_ESP_INV_SPI	0x01	/* Invert the sense of spi. */
+#define XT_ESP_INV_MASK	0x01	/* All possible flags. */
+
+#endif /*_XT_ESP_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_esp.h b/include/linux/netfilter_ipv4/ipt_esp.h
index c782a83..78296e7 100644
--- a/include/linux/netfilter_ipv4/ipt_esp.h
+++ b/include/linux/netfilter_ipv4/ipt_esp.h
@@ -1,16 +1,10 @@
 #ifndef _IPT_ESP_H
 #define _IPT_ESP_H
 
-struct ipt_esp
-{
-	u_int32_t spis[2];			/* Security Parameter Index */
-	u_int8_t  invflags;			/* Inverse flags */
-};
+#include <linux/netfilter/xt_esp.h>
 
-
-
-/* Values for "invflags" field in struct ipt_esp. */
-#define IPT_ESP_INV_SPI		0x01	/* Invert the sense of spi. */
-#define IPT_ESP_INV_MASK	0x01	/* All possible flags. */
+#define ipt_esp xt_esp
+#define IPT_ESP_INV_SPI		XT_ESP_INV_SPI
+#define IPT_ESP_INV_MASK	XT_ESP_INV_MASK
 
 #endif /*_IPT_ESP_H*/
diff --git a/include/linux/netfilter_ipv6/ip6t_esp.h b/include/linux/netfilter_ipv6/ip6t_esp.h
index a91b6ab..f62eaf5 100644
--- a/include/linux/netfilter_ipv6/ip6t_esp.h
+++ b/include/linux/netfilter_ipv6/ip6t_esp.h
@@ -1,14 +1,10 @@
 #ifndef _IP6T_ESP_H
 #define _IP6T_ESP_H
 
-struct ip6t_esp
-{
-	u_int32_t spis[2];			/* Security Parameter Index */
-	u_int8_t  invflags;			/* Inverse flags */
-};
+#include <linux/netfilter/xt_esp.h>
 
-/* Values for "invflags" field in struct ip6t_esp. */
-#define IP6T_ESP_INV_SPI		0x01	/* Invert the sense of spi. */
-#define IP6T_ESP_INV_MASK	0x01	/* All possible flags. */
+#define ip6t_esp xt_esp
+#define IP6T_ESP_INV_SPI	XT_ESP_INV_SPI
+#define IP6T_ESP_INV_MASK	XT_ESP_INV_MASK
 
 #endif /*_IP6T_ESP_H*/
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 882b842..ebbd644 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -272,12 +272,12 @@ config IP_NF_MATCH_DSCP
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_MATCH_AH_ESP
-	tristate "AH/ESP match support"
+config IP_NF_MATCH_AH
+	tristate "AH match support"
 	depends on IP_NF_IPTABLES
 	help
-	  These two match extensions (`ah' and `esp') allow you to match a
-	  range of SPIs inside AH or ESP headers of IPSec packets.
+	  This match extension allows you to match a range of SPIs
+	  inside AH header of IPSec packets.
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index f2cd9a6..09ae167 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -59,7 +59,7 @@ obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos
 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
 obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
 obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
-obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
+obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
 
diff --git a/net/ipv4/netfilter/ipt_esp.c b/net/ipv4/netfilter/ipt_esp.c
deleted file mode 100644
index 3840b41..0000000
--- a/net/ipv4/netfilter/ipt_esp.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* Kernel module to match ESP parameters. */
-
-/* (C) 1999-2000 Yon Uriarte <yon@astaro.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-
-#include <linux/netfilter_ipv4/ipt_esp.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Yon Uriarte <yon@astaro.de>");
-MODULE_DESCRIPTION("iptables ESP SPI match module");
-
-#ifdef DEBUG_CONNTRACK
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
-/* Returns 1 if the spi is matched by the range, 0 otherwise */
-static inline int
-spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
-{
-	int r=0;
-        duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
-        	min,spi,max);
-	r=(spi >= min && spi <= max) ^ invert;
-	duprintf(" result %s\n",r? "PASS" : "FAILED");
-	return r;
-}
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const struct xt_match *match,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-	struct ip_esp_hdr _esp, *eh;
-	const struct ipt_esp *espinfo = matchinfo;
-
-	/* Must not be a fragment. */
-	if (offset)
-		return 0;
-
-	eh = skb_header_pointer(skb, protoff,
-				sizeof(_esp), &_esp);
-	if (eh == NULL) {
-		/* We've been asked to examine this packet, and we
-		 * can't.  Hence, no choice but to drop.
-		 */
-		duprintf("Dropping evil ESP tinygram.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	return spi_match(espinfo->spis[0], espinfo->spis[1],
-			 ntohl(eh->spi),
-			 !!(espinfo->invflags & IPT_ESP_INV_SPI));
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-checkentry(const char *tablename,
-	   const void *ip_void,
-	   const struct xt_match *match,
-	   void *matchinfo,
-	   unsigned int matchinfosize,
-	   unsigned int hook_mask)
-{
-	const struct ipt_esp *espinfo = matchinfo;
-
-	/* Must specify no unknown invflags */
-	if (espinfo->invflags & ~IPT_ESP_INV_MASK) {
-		duprintf("ipt_esp: unknown flags %X\n", espinfo->invflags);
-		return 0;
-	}
-	return 1;
-}
-
-static struct ipt_match esp_match = {
-	.name		= "esp",
-	.match		= match,
-	.matchsize	= sizeof(struct ipt_esp),
-	.proto		= IPPROTO_ESP,
-	.checkentry	= checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init ipt_esp_init(void)
-{
-	return ipt_register_match(&esp_match);
-}
-
-static void __exit ipt_esp_fini(void)
-{
-	ipt_unregister_match(&esp_match);
-}
-
-module_init(ipt_esp_init);
-module_exit(ipt_esp_fini);
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 98f7875..bdd569f 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -115,11 +115,11 @@ config IP6_NF_MATCH_IPV6HEADER
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_AHESP
-	tristate "AH/ESP match support"
+config IP6_NF_MATCH_AH
+	tristate "AH match support"
 	depends on IP6_NF_IPTABLES
 	help
-	  This module allows one to match AH and ESP packets.
+	  This module allows one to match AH packets.
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 8436a1a..c387170 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt
 obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
 obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
 obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
-obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
+obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c
deleted file mode 100644
index 36bedad..0000000
--- a/net/ipv6/netfilter/ip6t_esp.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/* Kernel module to match ESP parameters. */
-/* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/types.h>
-#include <net/checksum.h>
-#include <net/ipv6.h>
-
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv6/ip6t_esp.h>
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("IPv6 ESP match");
-MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-/* Returns 1 if the spi is matched by the range, 0 otherwise */
-static inline int
-spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
-{
-	int r=0;
-	DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
-	       min,spi,max);
-	r=(spi >= min && spi <= max) ^ invert;
-	DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
-	return r;
-}
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const struct xt_match *match,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-	struct ip_esp_hdr _esp, *eh;
-	const struct ip6t_esp *espinfo = matchinfo;
-	unsigned int ptr;
-
-	/* Make sure this isn't an evil packet */
-	/*DEBUGP("ipv6_esp entered \n");*/
-
-	if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP, NULL) < 0)
-		return 0;
-
-	eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp);
-	if (eh == NULL) {
-		*hotdrop = 1;
-		return 0;
-	}
-
-	DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(eh->spi), ntohl(eh->spi));
-
-	return (eh != NULL)
-		&& spi_match(espinfo->spis[0], espinfo->spis[1],
-			      ntohl(eh->spi),
-			      !!(espinfo->invflags & IP6T_ESP_INV_SPI));
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-checkentry(const char *tablename,
-	   const void *ip,
-	   const struct xt_match *match,
-	   void *matchinfo,
-	   unsigned int matchinfosize,
-	   unsigned int hook_mask)
-{
-	const struct ip6t_esp *espinfo = matchinfo;
-
-	if (espinfo->invflags & ~IP6T_ESP_INV_MASK) {
-		DEBUGP("ip6t_esp: unknown flags %X\n",
-			 espinfo->invflags);
-		return 0;
-	}
-	return 1;
-}
-
-static struct ip6t_match esp_match = {
-	.name		= "esp",
-	.match		= match,
-	.matchsize	= sizeof(struct ip6t_esp),
-	.checkentry	= checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init ip6t_esp_init(void)
-{
-	return ip6t_register_match(&esp_match);
-}
-
-static void __exit ip6t_esp_fini(void)
-{
-	ip6t_unregister_match(&esp_match);
-}
-
-module_init(ip6t_esp_init);
-module_exit(ip6t_esp_fini);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 332acb3..5fe5189 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -231,6 +231,15 @@ config NETFILTER_XT_MATCH_DCCP
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_MATCH_ESP
+	tristate '"ESP" match support'
+	depends on NETFILTER_XTABLES
+	help
+	  This match extension allows you to match a range of SPIs
+	  inside ESP header of IPSec packets.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_HELPER
 	tristate '"helper" match support'
 	depends on NETFILTER_XTABLES
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 9558727..8f02486 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTE
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
diff --git a/net/netfilter/xt_esp.c b/net/netfilter/xt_esp.c
new file mode 100644
index 0000000..9dad628
--- /dev/null
+++ b/net/netfilter/xt_esp.c
@@ -0,0 +1,136 @@
+/* Kernel module to match ESP parameters. */
+
+/* (C) 1999-2000 Yon Uriarte <yon@astaro.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+
+#include <linux/netfilter/xt_esp.h>
+#include <linux/netfilter/x_tables.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yon Uriarte <yon@astaro.de>");
+MODULE_DESCRIPTION("x_tables ESP SPI match module");
+MODULE_ALIAS("ipt_esp");
+MODULE_ALIAS("ip6t_esp");
+
+#if 0
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+	int r = 0;
+	duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ',
+		 min, spi, max);
+	r = (spi >= min && spi <= max) ^ invert;
+	duprintf(" result %s\n", r ? "PASS" : "FAILED");
+	return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const struct xt_match *match,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+	struct ip_esp_hdr _esp, *eh;
+	const struct xt_esp *espinfo = matchinfo;
+
+	/* Must not be a fragment. */
+	if (offset)
+		return 0;
+
+	eh = skb_header_pointer(skb, protoff, sizeof(_esp), &_esp);
+	if (eh == NULL) {
+		/* We've been asked to examine this packet, and we
+		 * can't.  Hence, no choice but to drop.
+		 */
+		duprintf("Dropping evil ESP tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	return spi_match(espinfo->spis[0], espinfo->spis[1], ntohl(eh->spi),
+			 !!(espinfo->invflags & XT_ESP_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const void *ip_void,
+	   const struct xt_match *match,
+	   void *matchinfo,
+	   unsigned int matchinfosize,
+	   unsigned int hook_mask)
+{
+	const struct xt_esp *espinfo = matchinfo;
+
+	if (espinfo->invflags & ~XT_ESP_INV_MASK) {
+		duprintf("xt_esp: unknown flags %X\n", espinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct xt_match esp_match = {
+	.name		= "esp",
+	.family		= AF_INET,
+	.proto		= IPPROTO_ESP,
+	.match		= &match,
+	.matchsize	= sizeof(struct xt_esp),
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_match esp6_match = {
+	.name		= "esp",
+	.family		= AF_INET6,
+	.proto		= IPPROTO_ESP,
+	.match		= &match,
+	.matchsize	= sizeof(struct xt_esp),
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+
+static int __init xt_esp_init(void)
+{
+	int ret;
+	ret = xt_register_match(&esp_match);
+	if (ret)
+		return ret;
+
+	ret = xt_register_match(&esp6_match);
+	if (ret)
+		xt_unregister_match(&esp_match);
+
+	return ret;
+}
+
+static void __exit xt_esp_cleanup(void)
+{
+	xt_unregister_match(&esp_match);
+	xt_unregister_match(&esp6_match);
+}
+
+module_init(xt_esp_init);
+module_exit(xt_esp_cleanup);

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [NETFILTER 00/04]: Netfilter Update
  2006-03-31 10:28   ` Patrick McHardy
@ 2006-03-31 10:32     ` David S. Miller
  0 siblings, 0 replies; 8+ messages in thread
From: David S. Miller @ 2006-03-31 10:32 UTC (permalink / raw)
  To: kaber; +Cc: netfilter-devel

From: Patrick McHardy <kaber@trash.net>
Date: Fri, 31 Mar 2006 12:28:56 +0200

> Sorry, I accidentally missed the first patch. I've attached it to
> this mail, with it the patches apply cleanly against the current tree.
> If you want me to resubmit the entire set anyway please say so.
> Thanks.

Ok, this is fine.

I already pushed to Linus tonight, so I'll add these in
some time tomorrow.

Thanks again.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2006-03-31 10:32 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-03-31  1:09 [NETFILTER 00/04]: Netfilter Update Patrick McHardy
2006-03-31  1:09 ` [NETFILTER 01/04]: x_tables: unify IPv4/IPv6 multiport match Patrick McHardy
2006-03-31  1:09 ` [NETFILTER 02/04]: fix ifdef for connmark support in nf_conntrack_netlink Patrick McHardy
2006-03-31  1:09 ` [NETFILTER 03/04]: {ip, nf}_conntrack_netlink: fix expectation notifier unregistration Patrick McHardy
2006-03-31  1:09 ` [NETFILTER 04/04]: iptables 32bit compat layer Patrick McHardy
2006-03-31 10:15 ` [NETFILTER 00/04]: Netfilter Update David S. Miller
2006-03-31 10:28   ` Patrick McHardy
2006-03-31 10:32     ` David S. Miller

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.