All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: NetFilter unclean modue in 2.6.x kernels
       [not found] <200501220013.56429.sov.rbsec@gmail.com>
@ 2005-01-21 23:33 ` Harald Welte
  2005-01-24  8:40   ` Jozsef Kadlecsik
  0 siblings, 1 reply; 7+ messages in thread
From: Harald Welte @ 2005-01-21 23:33 UTC (permalink / raw)
  To: Oleg V. Sapon; +Cc: netfilter-devel

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

On Sat, Jan 22, 2005 at 12:13:56AM +0300, Oleg V. Sapon wrote:
>  Can you help locate unclean module for 2.6.x kernel or we must use
>  source files from 2.6.0-test4?

I fear nobody did that port to recent 2.6.x and put it into
patch-o-matic :(

I just did that with the old code from 2.6.0-testX.  I didn't have the
time to give it any runtime testing, but at least it compiled (after
fixing up some includes).

> 	Our company can test patches and even (if I can) sponsor this work.

Please test the code that is now (Version 3605) in patch-o-matic-ng.

> Oleg V. Sapon.

-- 
- Harald Welte <laforge@netfilter.org>             http://www.netfilter.org/
============================================================================
  "Fragmentation is like classful addressing -- an interesting early
   architectural error that shows how much experimentation was going
   on while IP was being designed."                    -- Paul Vixie

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

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

* Re: NetFilter unclean modue in 2.6.x kernels
  2005-01-21 23:33 ` NetFilter unclean modue in 2.6.x kernels Harald Welte
@ 2005-01-24  8:40   ` Jozsef Kadlecsik
  2005-01-24  8:57     ` Harald Welte
  2005-01-24 10:21     ` Pablo Neira
  0 siblings, 2 replies; 7+ messages in thread
From: Jozsef Kadlecsik @ 2005-01-24  8:40 UTC (permalink / raw)
  To: Harald Welte; +Cc: Oleg V. Sapon, netfilter-devel

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1501 bytes --]

Hi Harald,

On Sat, 22 Jan 2005, Harald Welte wrote:

> On Sat, Jan 22, 2005 at 12:13:56AM +0300, Oleg V. Sapon wrote:
> >  Can you help locate unclean module for 2.6.x kernel or we must use
> >  source files from 2.6.0-test4?
>
> I fear nobody did that port to recent 2.6.x and put it into
> patch-o-matic :(
>
> I just did that with the old code from 2.6.0-testX.  I didn't have the
> time to give it any runtime testing, but at least it compiled (after
> fixing up some includes).

I also ported the unclean patch to 2.6 some time ago. The main reason I
did not post it was the slightly modified API.

The port I created verifies the checksums as well, relying on hardware
checksums when possible. It also flags the clean packet in nfcache (that
is where the API was changed) so that the TCP connection tracking code can
rely on the results of the unclean match:

iptables -t raw -A PREROUTING -m unclean -j DROP

If there are plans to submit the unclean match into the kernel, I think
something like my port should be considered.

In order to make the unclean patch acceptable for kernel inclusion, we
could probably add a '--check-reserved' flag to it which would enable all
checkings, while the default would skip checking the reserved bits.

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@sunserv.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary

[-- Attachment #2: unclean.patch --]
[-- Type: TEXT/PLAIN, Size: 37600 bytes --]

diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/include/linux/netfilter.h linux-2.6.9-unclean/include/linux/netfilter.h
--- linux-2.6.9-orig/include/linux/netfilter.h	2004-10-18 23:54:08.000000000 +0200
+++ linux-2.6.9-unclean/include/linux/netfilter.h	2004-12-16 09:59:54.000000000 +0100
@@ -24,6 +24,8 @@
    <= 0x2000 is used for protocol-flags. */
 #define NFC_UNKNOWN 0x4000
 #define NFC_ALTERED 0x8000
+/* #define NFC_TRACE 0x10000 */
+#define NFC_CLEAN   0x20000
 
 #ifdef __KERNEL__
 #include <linux/config.h>
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/include/linux/netfilter_ipv4/ip_tables.h linux-2.6.9-unclean/include/linux/netfilter_ipv4/ip_tables.h
--- linux-2.6.9-orig/include/linux/netfilter_ipv4/ip_tables.h	2004-10-18 23:54:31.000000000 +0200
+++ linux-2.6.9-unclean/include/linux/netfilter_ipv4/ip_tables.h	2004-12-16 09:47:34.000000000 +0100
@@ -355,6 +355,7 @@
 		     const struct net_device *in,
 		     const struct net_device *out,
 		     const void *matchinfo,
+		     u_int32_t *nfcache,
 		     int offset,
 		     int *hotdrop);
 
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/Kconfig linux-2.6.9-unclean/net/ipv4/netfilter/Kconfig
--- linux-2.6.9-orig/net/ipv4/netfilter/Kconfig	2004-10-18 23:54:55.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/Kconfig	2004-12-16 09:58:18.000000000 +0100
@@ -610,6 +610,29 @@
 	  <file:Documentation/modules.txt>.  If unsure, say `N'.
 	  help
 
+config IP_NF_MATCH_UNCLEAN
+	tristate  'unclean match support'
+	depends on IP_NF_RAW
+	help
+	  Unclean packet matching matches any strange or invalid packets,
+	  by looking at a series of fields in the IP, TCP, UDP and ICMP 
+	  headers.
+
+	  If you want to compile it as a module, say M here and read
+	  Documentation/modules.txt.  If unsure, say `N'.
+
+config IP_NF_MATCH_UNCLEAN_HWCSUM
+	bool 'unclean match supporting hardware checksumming'
+	default n
+	depends on IP_NF_MATCH_UNCLEAN
+	help
+	  With this option enabled, the unclean match will be able
+	  to use the hardware checksums generated by the network
+	  interfaces (if those support HW checksumming) with the price
+	  that the match can then be used only in the PREROUTING chain.
+	  If the option is disabled, the match itself have to compute
+	  the checksums but it can be used in any chain.
+
 config IP_NF_TARGET_NOTRACK
 	tristate  'NOTRACK target support'
 	depends on IP_NF_RAW
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/Makefile linux-2.6.9-unclean/net/ipv4/netfilter/Makefile
--- linux-2.6.9-orig/net/ipv4/netfilter/Makefile	2004-10-18 23:53:43.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/Makefile	2004-12-16 09:47:50.000000000 +0100
@@ -67,6 +67,7 @@
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
 obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
 obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o
+obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
 
 # targets
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.6.9-unclean/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2004-10-18 23:55:29.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2004-12-16 10:02:26.000000000 +0100
@@ -776,6 +776,10 @@
 	struct tcphdr _tcph, *th;
 	unsigned int tcplen = skb->len - iph->ihl * 4;
 	u_int8_t tcpflags;
+	
+	/* Already verified by ipt_unclean? */
+	if (skb->nfcache & NFC_CLEAN)
+		return NF_ACCEPT;
 
 	/* Smaller that minimal TCP header? */
 	th = skb_header_pointer(skb, iph->ihl * 4,
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ip_tables.c linux-2.6.9-unclean/net/ipv4/netfilter/ip_tables.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ip_tables.c	2004-10-18 23:53:43.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ip_tables.c	2004-12-16 09:47:34.000000000 +0100
@@ -238,11 +238,13 @@
 	     const struct sk_buff *skb,
 	     const struct net_device *in,
 	     const struct net_device *out,
+	     u_int32_t *nfcache,
 	     int offset,
 	     int *hotdrop)
 {
 	/* Stop iteration if it doesn't match */
-	if (!m->u.kernel.match->match(skb, in, out, m->data, offset, hotdrop))
+	if (!m->u.kernel.match->match(skb, in, out, m->data,
+				      nfcache, offset, hotdrop))
 		return 1;
 	else
 		return 0;
@@ -318,6 +320,7 @@
 
 			if (IPT_MATCH_ITERATE(e, do_match,
 					      *pskb, in, out,
+					      &(*pskb)->nfcache,
 					      offset, &hotdrop) != 0)
 				goto no_match;
 
@@ -1491,6 +1494,7 @@
 	  const struct net_device *in,
 	  const struct net_device *out,
 	  const void *matchinfo,
+	  u_int32_t *nfcache,
 	  int offset,
 	  int *hotdrop)
 {
@@ -1572,6 +1576,7 @@
 	  const struct net_device *in,
 	  const struct net_device *out,
 	  const void *matchinfo,
+	  u_int32_t *nfcache,
 	  int offset,
 	  int *hotdrop)
 {
@@ -1645,6 +1650,7 @@
 	   const struct net_device *in,
 	   const struct net_device *out,
 	   const void *matchinfo,
+	   u_int32_t *nfcache,
 	   int offset,
 	   int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_addrtype.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_addrtype.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_addrtype.c	2004-10-18 23:53:06.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_addrtype.c	2004-12-16 09:47:34.000000000 +0100
@@ -29,7 +29,7 @@
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
 		 const struct net_device *out, const void *matchinfo,
-		 int offset, int *hotdrop)
+		 u_int32_t *nfcache, int offset, int *hotdrop)
 {
 	const struct ipt_addrtype_info *info = matchinfo;
 	const struct iphdr *iph = skb->nh.iph;
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_ah.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ah.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_ah.c	2004-10-18 23:54:37.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ah.c	2004-12-16 09:47:34.000000000 +0100
@@ -40,6 +40,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_comment.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_comment.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_comment.c	2004-10-18 23:54:27.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_comment.c	2004-12-16 09:47:34.000000000 +0100
@@ -18,6 +18,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_conntrack.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_conntrack.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_conntrack.c	2004-10-18 23:55:07.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_conntrack.c	2004-12-16 09:47:34.000000000 +0100
@@ -23,6 +23,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_dscp.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_dscp.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_dscp.c	2004-10-18 23:54:39.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_dscp.c	2004-12-16 09:47:34.000000000 +0100
@@ -21,7 +21,7 @@
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
 		 const struct net_device *out, const void *matchinfo,
-		 int offset, int *hotdrop)
+		 u_int32_t *nfcache, int offset, int *hotdrop)
 {
 	const struct ipt_dscp_info *info = matchinfo;
 	const struct iphdr *iph = skb->nh.iph;
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_ecn.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ecn.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_ecn.c	2004-10-18 23:54:08.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ecn.c	2004-12-16 09:47:34.000000000 +0100
@@ -67,7 +67,7 @@
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
 		 const struct net_device *out, const void *matchinfo,
-		 int offset, int *hotdrop)
+		 u_int32_t *nfcache, int offset, int *hotdrop)
 {
 	const struct ipt_ecn_info *info = matchinfo;
 
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_esp.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_esp.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_esp.c	2004-10-18 23:54:24.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_esp.c	2004-12-16 09:47:34.000000000 +0100
@@ -41,6 +41,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_helper.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_helper.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_helper.c	2004-10-18 23:55:36.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_helper.c	2004-12-16 09:47:34.000000000 +0100
@@ -34,6 +34,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_iprange.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_iprange.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_iprange.c	2004-10-18 23:54:20.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_iprange.c	2004-12-16 09:47:34.000000000 +0100
@@ -28,6 +28,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset, int *hotdrop)
 {
 	const struct ipt_iprange_info *info = matchinfo;
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_length.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_length.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_length.c	2004-10-18 23:54:40.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_length.c	2004-12-16 09:47:34.000000000 +0100
@@ -21,6 +21,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_limit.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_limit.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_limit.c	2004-10-18 23:53:09.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_limit.c	2004-12-16 09:47:34.000000000 +0100
@@ -67,6 +67,7 @@
 		const struct net_device *in,
 		const struct net_device *out,
 		const void *matchinfo,
+		u_int32_t *nfcache,
 		int offset,
 		int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_mac.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_mac.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_mac.c	2004-10-18 23:53:13.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_mac.c	2004-12-16 09:47:34.000000000 +0100
@@ -24,6 +24,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_mark.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_mark.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_mark.c	2004-10-18 23:55:36.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_mark.c	2004-12-16 09:47:34.000000000 +0100
@@ -22,6 +22,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_multiport.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_multiport.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_multiport.c	2004-10-18 23:53:23.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_multiport.c	2004-12-16 09:47:34.000000000 +0100
@@ -51,6 +51,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_owner.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_owner.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_owner.c	2004-10-18 23:55:24.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_owner.c	2004-12-16 09:47:34.000000000 +0100
@@ -125,6 +125,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_physdev.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_physdev.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_physdev.c	2004-10-18 23:53:45.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_physdev.c	2004-12-16 09:47:34.000000000 +0100
@@ -25,6 +25,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_pkttype.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_pkttype.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_pkttype.c	2004-10-18 23:55:36.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_pkttype.c	2004-12-16 09:47:34.000000000 +0100
@@ -21,6 +21,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_realm.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_realm.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_realm.c	2004-10-18 23:54:30.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_realm.c	2004-12-16 09:47:34.000000000 +0100
@@ -26,6 +26,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_recent.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_recent.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_recent.c	2004-10-18 23:53:21.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_recent.c	2004-12-16 09:47:34.000000000 +0100
@@ -103,6 +103,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop);
 
@@ -317,7 +318,7 @@
 	skb->nh.iph->daddr = 0;
 	/* Clear ttl since we have no way of knowing it */
 	skb->nh.iph->ttl = 0;
-	match(skb,NULL,NULL,info,0,NULL);
+	match(skb,NULL,NULL,info,NULL,0,NULL);
 
 	kfree(skb->nh.iph);
 out_free_skb:
@@ -356,6 +357,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_sctp.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_sctp.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_sctp.c	2004-10-18 23:53:51.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_sctp.c	2004-12-16 09:47:34.000000000 +0100
@@ -117,6 +117,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_state.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_state.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_state.c	2004-10-18 23:55:35.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_state.c	2004-12-16 09:47:34.000000000 +0100
@@ -23,6 +23,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_tcpmss.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_tcpmss.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_tcpmss.c	2004-10-18 23:53:21.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_tcpmss.c	2004-12-16 09:47:34.000000000 +0100
@@ -78,6 +78,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_tos.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_tos.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_tos.c	2004-10-18 23:55:28.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_tos.c	2004-12-16 09:47:34.000000000 +0100
@@ -22,6 +22,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
+      u_int32_t *nfcache,
       int offset,
       int *hotdrop)
 {
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_ttl.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ttl.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_ttl.c	2004-10-18 23:55:35.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ttl.c	2004-12-16 09:47:34.000000000 +0100
@@ -21,7 +21,7 @@
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
 		 const struct net_device *out, const void *matchinfo,
-		 int offset, int *hotdrop)
+		 u_int32_t *nfcache, int offset, int *hotdrop)
 {
 	const struct ipt_ttl_info *info = matchinfo;
 
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_unclean.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_unclean.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_unclean.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_unclean.c	2005-01-24 08:00:35.000000000 +0100
@@ -0,0 +1,687 @@
+/* Kernel module to match suspect packets. */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/tcp.h>
+#include <linux/icmp.h>
+#include <net/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#ifdef CONFIG_IP_NF_MATCH_UNCLEAN_HWCSUM
+#define may_use_csum(skb)	(skb->ip_summed == CHECKSUM_HW)
+#else
+#define may_use_csum(skb)	0
+#endif
+
+#define limpk(format, args...)						 \
+do {									 \
+	if (net_ratelimit())						 \
+		printk("ipt_unclean: %s" format,			 \
+		       embedded ? "(in embedded packet) " : "" ,	 \
+		       ## args);  \
+} while(0)
+
+enum icmp_error_status
+{
+	ICMP_MAY_BE_ERROR,
+	ICMP_IS_ERROR,
+	ICMP_NOT_ERROR
+};
+
+struct icmp_info
+{
+	size_t min_len, max_len;
+	enum icmp_error_status err;
+	u_int8_t min_code, max_code;
+};
+
+static int
+check_ip(const struct sk_buff *skb, size_t length,
+	 int embedded, size_t seen);
+
+/* ICMP-specific checks. */
+static int
+check_icmp(const struct sk_buff *skb,
+	   u_int16_t datalen,
+	   unsigned int offset,
+	   int more_frags,
+	   int embedded,
+	   u_int16_t seen)
+{
+	struct icmphdr _icmph, *icmph;
+	static struct icmp_info info[]
+		= { [ICMP_ECHOREPLY]
+		    = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
+		    [ICMP_DEST_UNREACH]
+		    = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 15 },
+		    [ICMP_SOURCE_QUENCH]
+		    = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 0 },
+		    [ICMP_REDIRECT]
+		    = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 3 },
+		    [ICMP_ECHO]
+		    = { 8, 65536, ICMP_NOT_ERROR, 0, 0  },
+		    /* Router advertisement. */
+		    [9]
+		    = { 8, 8 + 255 * 8, ICMP_NOT_ERROR, 0, 0 },
+		    /* Router solicitation. */
+		    [10]
+		    = { 8, 8, ICMP_NOT_ERROR, 0, 0 },
+		    [ICMP_TIME_EXCEEDED]
+		    = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 1  },
+		    [ICMP_PARAMETERPROB]
+		    = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 1 },
+		    [ICMP_TIMESTAMP]
+		    = { 20, 20, ICMP_NOT_ERROR, 0, 0 },
+		    [ICMP_TIMESTAMPREPLY]
+		    = { 20, 20, ICMP_NOT_ERROR, 0, 0 },
+		    [ICMP_INFO_REQUEST]
+		    = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
+		    [ICMP_INFO_REPLY]
+		    = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
+		    [ICMP_ADDRESS]
+		    = { 12, 12, ICMP_NOT_ERROR, 0, 0 },
+		    [ICMP_ADDRESSREPLY]
+		    = { 12, 12, ICMP_NOT_ERROR, 0, 0 } };
+
+	/* Can't do anything if it's a fragment. */
+	if (offset)
+		return 1;
+
+	/* Must cover type and code. */
+	if (datalen < 2) {
+		limpk("ICMP len=%u too short\n", datalen);
+		return 0;
+	}
+	
+	/* Must cover the ICMP header */
+	icmph = skb_header_pointer(skb, seen, sizeof(_icmph), &_icmph);
+	if (icmph == NULL) {
+		limpk("Evil ICMP tinygram\n");
+		return 0;
+	}
+	
+	/* If not embedded. */
+	if (!embedded) {
+		/* Bad checksum?  Don't print, just ignore. */
+		if (!more_frags
+		    && (u16)csum_fold(skb_checksum(skb, seen, datalen, 0)))
+			return 0;
+
+		/* CHECK: Truncated ICMP (even if first fragment). */
+		if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
+		    && info[icmph->type].min_len != 0
+		    && datalen < info[icmph->type].min_len) {
+			limpk("ICMP type %u len %u too short\n",
+			      icmph->type, datalen);
+			return 0;
+		}
+
+		/* CHECK: Check within known error ICMPs. */
+		if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
+		    && info[icmph->type].err == ICMP_IS_ERROR) {
+		    	/* CHECK: Check inner packet. */
+			if (!check_ip(skb, datalen - 8, 1, seen + 8))
+				return 0;
+		}
+	} else {
+		/* CHECK: Can't embed ICMP unless known non-error. */
+		if (icmph->type >= sizeof(info)/sizeof(struct icmp_info)
+		    || info[icmph->type].err != ICMP_NOT_ERROR) {
+			limpk("ICMP type %u not embeddable\n",
+			      icmph->type);
+			return 0;
+		}
+	}
+
+	/* CHECK: Invalid ICMP codes. */
+	if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
+	    && (icmph->code < info[icmph->type].min_code
+		|| icmph->code > info[icmph->type].max_code)) {
+		limpk("ICMP type=%u code=%u\n",
+		      icmph->type, icmph->code);
+		return 0;
+	}
+
+	/* CHECK: Above maximum length. */
+	if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
+	    && info[icmph->type].max_len != 0
+	    && datalen > info[icmph->type].max_len) {
+		limpk("ICMP type=%u too long: %u bytes\n",
+		      icmph->type, datalen);
+		return 0;
+	}
+
+	switch (icmph->type) {
+	case ICMP_PARAMETERPROB: {
+		/* CHECK: Problem param must be within error packet's
+		 * IP header. */
+		u_int32_t arg = ntohl(icmph->un.gateway);
+
+		if (icmph->code == 0) {
+			/* Code 0 means that upper 8 bits is pointer
+                           to problem. */
+			struct iphdr _iph, *iph;
+			
+			iph = skb_header_pointer(skb, seen + 8, 
+						 sizeof(_iph), &_iph);
+			if (iph == NULL) {
+				limpk("Evil ICMP PARAMPROB tinygram\n");
+				return 0;
+			}
+			if ((arg >> 24) >= iph->ihl*4) {
+				limpk("ICMP PARAMETERPROB ptr = %u\n",
+				      ntohl(icmph->un.gateway) >> 24);
+				return 0;
+			}
+			arg &= 0x00FFFFFF;
+		}
+
+		/* CHECK: Rest must be zero. */
+		if (arg) {
+			limpk("ICMP PARAMETERPROB nonzero arg = %u\n",
+			      arg);
+			return 0;
+		}
+		break;
+	}
+
+	case ICMP_TIME_EXCEEDED:
+	case ICMP_SOURCE_QUENCH:
+		/* CHECK: Unused must be zero. */
+		if (icmph->un.gateway != 0) {
+			limpk("ICMP type=%u unused = %u\n",
+			      icmph->type, ntohl(icmph->un.gateway));
+			return 0;
+		}
+		break;
+	}
+
+	return 1;
+}
+
+/* UDP-specific checks. */
+static int
+check_udp(const struct sk_buff *skb,
+	  const struct iphdr *iph,
+	  u_int16_t datalen,
+	  unsigned int offset,
+	  int more_frags,
+	  int embedded,
+	  u_int16_t seen)
+{
+	struct udphdr _udph, *udph;
+
+	/* Can't do anything if it's a fragment. */
+	if (offset)
+		return 1;
+
+	/* CHECK: Must cover UDP header. */
+	if (datalen < sizeof(struct udphdr)) {
+		limpk("UDP len=%u too short\n", datalen);
+		return 0;
+	}
+	udph = skb_header_pointer(skb, seen, sizeof(_udph), &_udph);
+	if (udph == NULL) {
+		limpk("Evil UDP tinygram\n");
+		return 0;
+	}
+
+	/* Bad checksum?  Don't print, just say it's unclean. */	                   
+	/* FIXME: SRC ROUTE packets won't match checksum --RR */
+	if (!more_frags && !embedded && udph->check
+	    && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_UDP,
+	    			 may_use_csum(skb) ? skb->csum
+				 : skb_checksum(skb, seen, datalen, 0)))
+		return 0;
+
+	/* CHECK: Destination port can't be zero. */
+	if (!udph->dest) {
+		limpk("UDP zero destination port\n");
+		return 0;
+	}
+
+	if (!more_frags) {
+		if (!embedded) {
+			/* CHECK: UDP length must match. */
+			if (ntohs(udph->len) != datalen) {
+				limpk("UDP len too short %u vs %u\n",
+				      ntohs(udph->len), datalen);
+				return 0;
+			}
+		} else {
+			/* CHECK: UDP length be >= this truncated pkt. */
+			if (ntohs(udph->len) < datalen) {
+				limpk("UDP len too long %u vs %u\n",
+				      ntohs(udph->len), datalen);
+				return 0;
+			}
+		}
+	} else {
+		/* CHECK: UDP length must be > this frag's length. */
+		if (ntohs(udph->len) <= datalen) {
+			limpk("UDP fragment len too short %u vs %u\n",
+			      ntohs(udph->len), datalen);
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+#define	TH_FIN	0x01
+#define	TH_SYN	0x02
+#define	TH_RST	0x04
+#define	TH_PUSH	0x08
+#define	TH_ACK	0x10
+#define	TH_URG	0x20
+#define	TH_ECE	0x40
+#define	TH_CWR	0x80
+
+/* table of valid flag combinations - ECE and CWR are always valid */
+static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] =
+{
+	[TH_SYN]			= 1,
+	[TH_SYN|TH_ACK]			= 1,
+	[TH_RST]			= 1,
+	[TH_RST|TH_ACK]			= 1,
+	[TH_RST|TH_ACK|TH_PUSH]		= 1,
+	[TH_FIN|TH_ACK]			= 1,
+	[TH_ACK]			= 1,
+	[TH_ACK|TH_PUSH]		= 1,
+	[TH_ACK|TH_URG]			= 1,
+	[TH_ACK|TH_URG|TH_PUSH]		= 1,
+	[TH_FIN|TH_ACK|TH_PUSH]		= 1,
+	[TH_FIN|TH_ACK|TH_URG]		= 1,
+	[TH_FIN|TH_ACK|TH_URG|TH_PUSH]	= 1
+};
+
+/* TCP-specific checks. */
+static int
+check_tcp(const struct sk_buff *skb,
+	  const struct iphdr *iph,
+	  u_int16_t datalen,
+	  unsigned int offset,
+	  int more_frags,
+	  int embedded,
+	  u_int16_t seen)
+{
+	struct tcphdr _tcph, *tcph;
+	u_int8_t _opt[60 - sizeof(_tcph)], *opt;
+	u_int8_t tcpflags;
+	int end_of_options = 0, optlen;
+	size_t i = sizeof(_tcph);
+
+	/* CHECK: Can't have offset=1: used to override TCP syn-checks. */
+	/* In fact, this is caught below (offset < 516). */
+
+	/* Can't do anything if it's a fragment. */
+	if (offset)
+		return 1;
+
+	/* CHECK: Smaller than minimal TCP hdr. */
+	if (datalen < sizeof(struct tcphdr)) {
+		if (!embedded) {
+			limpk("Packet length %u < TCP header.\n", datalen);
+			return 0;
+		}
+		/* Must have ports available (datalen >= 8), from check_ip */
+		i = 8;
+	}
+
+	tcph = skb_header_pointer(skb, seen, i, &_tcph);
+	if (tcph == NULL) {
+		limpk("Evil TCP tinygram\n");
+		return 0;
+	}
+	
+	/* CHECK: TCP ports inside ICMP error */
+	if (embedded && (!tcph->source || !tcph->dest)) {
+		limpk("Zero TCP ports %u/%u.\n",
+		      htons(tcph->source), htons(tcph->dest));
+		return 0;
+	}
+
+	/* CHECK: Smaller than actual TCP hdr. */
+	if (datalen < tcph->doff * 4) {
+		if (!embedded) {
+			limpk("Packet length %u < actual TCP header.\n",
+			      datalen);
+			return 0;
+		} else
+			return 1;
+	}
+
+	/* Bad checksum?  Don't print, just say it's unclean. */
+	/* FIXME: SRC ROUTE packets won't match checksum --RR */
+	if (!more_frags && !embedded
+	    && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_TCP,
+	    			 may_use_csum(skb) ? skb->csum
+				 : skb_checksum(skb, seen, datalen, 0)))
+		return 0;
+
+	/* CHECK: TCP ports non-zero */
+	if (!tcph->source || !tcph->dest) {
+		limpk("Zero TCP ports %u/%u.\n",
+		      htons(tcph->source), htons(tcph->dest));
+		return 0;
+	}
+
+	/* CHECK: TCP reserved bits zero. */
+	if(tcp_flag_word(tcph) & TCP_RESERVED_BITS) {
+		limpk("TCP reserved bits not zero\n");
+		return 0;
+	}
+
+	/* CHECK: TCP flags. */
+	tcpflags = (((u_int8_t *)tcph)[13] & ~(TH_ECE|TH_CWR));
+	if (!tcp_valid_flags[tcpflags]) {
+		limpk("TCP flags bad: %u\n", tcpflags);
+		return 0;
+	}
+
+	/* CHECK: malformed header size */
+	if (tcph->doff * 4 < sizeof(struct tcphdr)) {
+		limpk("Header size %u < minimal TCP header.\n", tcph->doff * 4);
+		return 0;
+	}
+
+	optlen = tcph->doff * 4 - sizeof(_tcph);
+	opt = skb_header_pointer(skb, seen + sizeof(_tcph), optlen, &_opt);
+	if (opt == NULL) {
+		limpk("Evil TCP packet with options.\n");
+		return 0;
+	}
+	for (i = 0; i < optlen; ) {
+		switch (opt[i]) {
+		case 0:
+			end_of_options = 1;
+			i++;
+			break;
+		case 1:
+			i++;
+			break;
+		default:
+			/* CHECK: options after EOO. */
+			if (end_of_options) {
+				limpk("TCP option %u after end\n",
+				      opt[i]);
+				return 0;
+			}
+			/* CHECK: options at tail. */
+			else if (i+1 >= optlen) {
+				limpk("TCP option %u at tail\n",
+				      opt[i]);
+				return 0;
+			}
+			/* CHECK: zero-length options. */
+			else if (opt[i+1] == 0) {
+				limpk("TCP option %u 0 len\n",
+				      opt[i]);
+				return 0;
+			}
+			/* CHECK: oversize options. */
+			else if (i + opt[i+1] > optlen) {
+				limpk("TCP option %u at %u too long\n",
+				      (unsigned int) opt[i], i);
+				return 0;
+			}
+			/* Move to next option */
+			i += opt[i+1];
+		}
+	}
+
+	return 1;
+}
+
+/* Returns 1 if ok */
+/* Standard IP checks. */
+static int
+check_ip(const struct sk_buff *skb, size_t length,
+	 int embedded, size_t seen)
+{
+	struct iphdr _iph, *iph;
+	u_int8_t _opt[60 - sizeof(struct iphdr)], *opt;
+	int end_of_options = 0, optlen;
+	size_t datalen;
+	unsigned int i, offset;
+
+	/* Should only happen for local outgoing raw-socket packets. */
+	/* CHECK: length >= ip header. */
+	if (length < sizeof(struct iphdr)) {
+		limpk("Packet length %u < IP header.\n", length);
+		return 0;
+	}
+	if (embedded) {
+		iph = skb_header_pointer(skb, seen, sizeof(_iph), &_iph);
+		if (iph == NULL) {
+			limpk("Evil IP packet.\n");
+			return 0;
+		}
+	} else
+		iph = skb->nh.iph;
+
+	/* Should only happen for local outgoing raw-socket packets. */
+	/* CHECK: length >= ip header size. */
+	if (length < iph->ihl * 4) {
+		limpk("Packet length %u < actual IP header.\n", length);
+		return 0;
+	}
+	
+	/* CHECK: malformed header size */
+	if (iph->ihl * 4 < sizeof(struct iphdr)) {
+		limpk("Header size %u < minimal IP header.\n", iph->ihl * 4);
+		return 0;
+	}
+
+	/* CHECK: Embedded packet must be at least
+	   length of iph + 8 bytes. */
+	if (embedded && length < iph->ihl * 4 + 8) {
+		limpk("ICMP error internal too short\n");
+		return 0;
+	}
+	
+	offset = ntohs(iph->frag_off) & IP_OFFSET;
+	optlen = iph->ihl * 4 - sizeof(struct iphdr);
+	datalen = length - iph->ihl * 4;
+
+	/* CHECK: Embedded fragment. */
+	if (embedded && offset) {
+		limpk("Embedded fragment.\n");
+		return 0;
+	}
+
+	opt = skb_header_pointer(skb, seen + sizeof(_iph), optlen, &_opt);
+	if (opt == NULL) {
+		limpk("Evil IP packet with options.\n");
+		return 0;
+	}
+	for (i = 0; i < optlen; ) {
+		switch (opt[i]) {
+		case 0:
+			end_of_options = 1;
+			i++;
+			break;
+		case 1:
+			i++;
+			break;
+		default:
+			/* CHECK: options after EOO. */
+			if (end_of_options) {
+				limpk("IP option %u after end\n",
+				      opt[i]);
+				return 0;
+			}
+			/* CHECK: options at tail. */
+			else if (i+1 >= optlen) {
+				limpk("IP option %u at tail\n",
+				      opt[i]);
+				return 0;
+			}
+			/* CHECK: zero-length or one-length options. */
+			else if (opt[i+1] < 2) {
+				limpk("IP option %u %u len\n",
+				      opt[i], opt[i+1]);
+				return 0;
+			}
+			/* CHECK: oversize options. */
+			else if (i + opt[i+1] > optlen) {
+				limpk("IP option %u at %u too long\n",
+				      opt[i], i);
+				return 0;
+			}
+			/* Move to next option */
+			i += opt[i+1];
+		}
+	}
+
+	/* Fragment checks. */
+
+	/* CHECK: More fragments, but doesn't fill 8-byte boundary. */
+	if ((ntohs(iph->frag_off) & IP_MF) && datalen % 8 != 0) {
+		limpk("Truncated fragment %u long.\n", datalen);
+		return 0;
+	}
+
+	/* CHECK: Oversize fragment a-la Ping of Death. */
+	if (offset * 8 + datalen > 65535) {
+		limpk("Oversize fragment to %u.\n", offset * 8);
+		return 0;
+	}
+
+	/* CHECK: Zero-sized fragments. */
+	if ((offset || (ntohs(iph->frag_off) & IP_MF))
+	    && datalen == 0) {
+		limpk("Zero size fragment offset=%u\n", offset);
+		return 0;
+	}
+
+	/* Note: we can have even middle fragments smaller than this:
+	   consider a large packet passing through a 600MTU then
+	   576MTU link: this gives a fragment of 24 data bytes.  But
+	   everyone packs fragments largest first, hence a fragment
+	   can't START before 576 - MAX_IP_HEADER_LEN. */
+
+	/* Used to be min-size 576: I recall Alan Cox saying ax25 goes
+	   down to 128 (576 taken from RFC 791: All hosts must be
+	   prepared to accept datagrams of up to 576 octets).  Use 128
+	   here. */
+#define MIN_LIKELY_MTU 128
+	/* CHECK: Min size of first frag = 128. */
+	if ((ntohs(iph->frag_off) & IP_MF)
+	    && offset == 0
+	    && ntohs(iph->tot_len) < MIN_LIKELY_MTU) {
+		limpk("First fragment size %u < %u\n", ntohs(iph->tot_len),
+		      MIN_LIKELY_MTU);
+		return 0;
+	}
+
+	/* CHECK: Min offset of frag = 128 - IP hdr len. */
+	if (offset && offset * 8 < MIN_LIKELY_MTU - iph->ihl * 4) {
+		limpk("Fragment starts at %u < %u\n", offset * 8,
+		      MIN_LIKELY_MTU - iph->ihl * 4);
+		return 0;
+	}
+
+	/* CHECK: Protocol specification non-zero. */
+	if (iph->protocol == 0) {
+		limpk("Zero protocol\n");
+		return 0;
+	}
+
+	/* CHECK: Do not use what is unused.
+	 * First bit of fragmentation flags should be unused.
+	 * May be used by OS fingerprinting tools.
+	 * 04 Jun 2002, Maciej Soltysiak, solt@dns.toxicfilms.tv
+	 */
+	if (ntohs(iph->frag_off)>>15) {
+		limpk("IP unused bit set\n");
+		return 0;
+	}
+
+	seen += iph->ihl * 4;
+	/* Per-protocol checks. */
+	switch (iph->protocol) {
+	case IPPROTO_ICMP:
+		return check_icmp(skb, datalen, offset,
+				  (ntohs(iph->frag_off) & IP_MF),
+				  embedded, seen);
+
+	case IPPROTO_UDP:
+		return check_udp(skb, iph, datalen, offset,
+				 (ntohs(iph->frag_off) & IP_MF),
+				 embedded, seen);
+
+	case IPPROTO_TCP:
+		return check_tcp(skb, iph, datalen, offset,
+				 (ntohs(iph->frag_off) & IP_MF),
+				 embedded, seen);
+	default:
+		/* Ignorance is bliss. */
+		return 1;
+	}
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      u_int32_t *nfcache,
+      int offset,
+      int *hotdrop)
+{
+	int res = check_ip(skb, skb->len, 0, 0);
+
+	/* Cache the negative result. */	
+	if (res)
+		*nfcache |= NFC_CLEAN;
+	
+	return (!res);
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const struct ipt_ip *ip,
+	   void *matchinfo,
+	   unsigned int matchsize,
+	   unsigned int hook_mask)
+{
+#ifdef CONFIG_IP_NF_MATCH_UNCLEAN_HWCSUM
+	/* Only valid in PREROUTING */
+	if (hook_mask & ~(1 << NF_IP_PRE_ROUTING)) {
+	    	printk("ipt_unclean: only valid in PREROUTING.\n");
+	    	return 0;
+	}
+#endif
+	if (matchsize != IPT_ALIGN(0))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match unclean_match = {
+	.name		= "unclean",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+
+static int __init init(void)
+{
+	return ipt_register_match(&unclean_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&unclean_match);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("iptables 'unclean' packets match module");

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

* Re: NetFilter unclean modue in 2.6.x kernels
  2005-01-24  8:40   ` Jozsef Kadlecsik
@ 2005-01-24  8:57     ` Harald Welte
  2005-01-24  9:13       ` Jozsef Kadlecsik
  2005-01-24 10:21     ` Pablo Neira
  1 sibling, 1 reply; 7+ messages in thread
From: Harald Welte @ 2005-01-24  8:57 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: Oleg V. Sapon, netfilter-devel

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

Hi Jozsef!

On Mon, Jan 24, 2005 at 09:40:51AM +0100, Jozsef Kadlecsik wrote:
> I also ported the unclean patch to 2.6 some time ago. The main reason I
> did not post it was the slightly modified API.
>
> [...]
> 
> If there are plans to submit the unclean match into the kernel, I think
> something like my port should be considered.

No, I think we're pretty sure that we don't want to have it in the
kernel again.

> Jozsef
-- 
- Harald Welte <laforge@netfilter.org>             http://www.netfilter.org/
============================================================================
  "Fragmentation is like classful addressing -- an interesting early
   architectural error that shows how much experimentation was going
   on while IP was being designed."                    -- Paul Vixie

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

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

* Re: NetFilter unclean modue in 2.6.x kernels
  2005-01-24  8:57     ` Harald Welte
@ 2005-01-24  9:13       ` Jozsef Kadlecsik
  2005-01-24  9:22         ` Harald Welte
  0 siblings, 1 reply; 7+ messages in thread
From: Jozsef Kadlecsik @ 2005-01-24  9:13 UTC (permalink / raw)
  To: Harald Welte; +Cc: Oleg V. Sapon, netfilter-devel

Hi Harald,

On Mon, 24 Jan 2005, Harald Welte wrote:

> > If there are plans to submit the unclean match into the kernel, I think
> > something like my port should be considered.
>
> No, I think we're pretty sure that we don't want to have it in the
> kernel again.

As far as I remember, the main concern was due to the ckecking of the
reserved fields, which can cause forward-incompatibility. Was something
else against the match? Just asking :-)

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@sunserv.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary

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

* Re: NetFilter unclean modue in 2.6.x kernels
  2005-01-24  9:13       ` Jozsef Kadlecsik
@ 2005-01-24  9:22         ` Harald Welte
  0 siblings, 0 replies; 7+ messages in thread
From: Harald Welte @ 2005-01-24  9:22 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: Oleg V. Sapon, netfilter-devel

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

On Mon, Jan 24, 2005 at 10:13:36AM +0100, Jozsef Kadlecsik wrote:

> As far as I remember, the main concern was due to the ckecking of the
> reserved fields, which can cause forward-incompatibility. Was something
> else against the match? Just asking :-)

yes, that's basically it, IIRC.

> Jozsef
-- 
- Harald Welte <laforge@netfilter.org>             http://www.netfilter.org/
============================================================================
  "Fragmentation is like classful addressing -- an interesting early
   architectural error that shows how much experimentation was going
   on while IP was being designed."                    -- Paul Vixie

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

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

* Re: NetFilter unclean modue in 2.6.x kernels
  2005-01-24  8:40   ` Jozsef Kadlecsik
  2005-01-24  8:57     ` Harald Welte
@ 2005-01-24 10:21     ` Pablo Neira
  2005-01-24 10:53       ` Jozsef Kadlecsik
  1 sibling, 1 reply; 7+ messages in thread
From: Pablo Neira @ 2005-01-24 10:21 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: Harald Welte, Oleg V. Sapon, netfilter-devel

Jozsef Kadlecsik wrote:

>Hi Harald,
>
>On Sat, 22 Jan 2005, Harald Welte wrote:
>
>  
>
>>On Sat, Jan 22, 2005 at 12:13:56AM +0300, Oleg V. Sapon wrote:
>>    
>>
>>> Can you help locate unclean module for 2.6.x kernel or we must use
>>> source files from 2.6.0-test4?
>>>      
>>>
>>I fear nobody did that port to recent 2.6.x and put it into
>>patch-o-matic :(
>>
>>I just did that with the old code from 2.6.0-testX.  I didn't have the
>>time to give it any runtime testing, but at least it compiled (after
>>fixing up some includes).
>>    
>>
>
>I also ported the unclean patch to 2.6 some time ago. The main reason I
>did not post it was the slightly modified API.
>
>The port I created verifies the checksums as well, relying on hardware
>checksums when possible. 
>

Hm, the error API makes sure that we don't start a session in the 
connection tracking with unclean packets (since kernel 2.6.6). So 
something like:

iptables -m state INVALID -j ULOG

should be enough to log evil packets.

The checkings aren't so strict as those that the unclean module used to 
do but with a couple of patches I could tighten that. Actually I 
remember a discussion with Jozsef about this. As far as I can remember 
he didn't like so much the idea of putting half of the unclean module there.

--
Pablo

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

* Re: NetFilter unclean modue in 2.6.x kernels
  2005-01-24 10:21     ` Pablo Neira
@ 2005-01-24 10:53       ` Jozsef Kadlecsik
  0 siblings, 0 replies; 7+ messages in thread
From: Jozsef Kadlecsik @ 2005-01-24 10:53 UTC (permalink / raw)
  To: Pablo Neira; +Cc: Harald Welte, Oleg V. Sapon, netfilter-devel

On Mon, 24 Jan 2005, Pablo Neira wrote:

> >The port I created verifies the checksums as well, relying on hardware
> >checksums when possible.
>
> Hm, the error API makes sure that we don't start a session in the
> connection tracking with unclean packets (since kernel 2.6.6). So
> something like:
>
> iptables -m state INVALID -j ULOG
>
> should be enough to log evil packets.
>
> The checkings aren't so strict as those that the unclean module used to
> do but with a couple of patches I could tighten that. Actually I
> remember a discussion with Jozsef about this. As far as I can remember
> he didn't like so much the idea of putting half of the unclean module there.

The routines behind the error API perform just the very minimum checkings
to make sure the packets can be processed by conntrack(/NAT) sanely. But
that is all they are required to do, therefore I'd oppone to move other
checkings from the unclean module to the error functions. The purpose of
the conntrack subsytems is to keep track of the connections as perfectly
as possible and nothing more. It must not implement filtering functions ,
because it's the task delegated to the filter(/raw) table.

Ideally, I'd like to see setups like:

- drop malformed (unclean) packets in the raw table, as early as
  possible, so they don't hit conntrack at all
- keep track of connections and doing so rely on the results of the
  unclean macth (if exists) to avoid double checkings
- mangle/nat/filter

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@sunserv.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary

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

end of thread, other threads:[~2005-01-24 10:53 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <200501220013.56429.sov.rbsec@gmail.com>
2005-01-21 23:33 ` NetFilter unclean modue in 2.6.x kernels Harald Welte
2005-01-24  8:40   ` Jozsef Kadlecsik
2005-01-24  8:57     ` Harald Welte
2005-01-24  9:13       ` Jozsef Kadlecsik
2005-01-24  9:22         ` Harald Welte
2005-01-24 10:21     ` Pablo Neira
2005-01-24 10:53       ` Jozsef Kadlecsik

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.