[PATCH] netfilter bugfixes.

Rusty Russell rusty@linuxcare.com.au
Fri, 14 Jul 2000 17:20:22 +1000


Linus, please apply.

This patch:

	Compatibility layer ping corruption bug		(Rusty)
	Sparc alignment bugfix				(Rusty)
	REJECT fix + TCP RST re-enable			(Rusty)
	ICMP REDIRECT suppression fix			(Rusty)
	ipqueue -W bugfixes				(James Morris,
							 Andrew Morton)

This breaks source compatibility for x86 (but not binary
compatibility), and both source and binary compatibility for platforms
where it didn't work before anyway 8).

Rusty.
--- working-2.4.0-test4-3/Documentation/Changes.~1~	Wed Jul 12 17:51:59 2000
+++ working-2.4.0-test4-3/Documentation/Changes	Fri Jul 14 16:38:57 2000
@@ -317,12 +317,12 @@
 
 Netfilter
 ---------
-o  http://netfilter.filewatcher.org/iptables-1.1.0.tar.bz2
-     <http://netfilter.filewatcher.org/iptables-1.1.0.tar.bz2>
-o  http://www.samba.org/netfilter/iptables-1.1.0.tar.bz2
-     <http://www.samba.org/netfilter/iptables-1.1.0.tar.bz2>
-o  http://netfilter.kernelnotes.org/iptables-1.1.0.tar.bz2
-     <http://netfilter.kernelnotes.org/iptables-1.1.0.tar.bz2>
+o  http://netfilter.filewatcher.org/iptables-1.1.1.tar.bz2
+     <http://netfilter.filewatcher.org/iptables-1.1.1.tar.bz2>
+o  http://www.samba.org/netfilter/iptables-1.1.1.tar.bz2
+     <http://www.samba.org/netfilter/iptables-1.1.1.tar.bz2>
+o  http://netfilter.kernelnotes.org/iptables-1.1.1.tar.bz2
+     <http://netfilter.kernelnotes.org/iptables-1.1.1.tar.bz2>
 
 Ip-route2
 ---------
diff -urN -X /tmp/fileOJlBE7 --minimal linux-2.4.0-test3-2/net/ipv4/netfilter/ip_fw_compat_masq.c working-2.4.0-test3-2/net/ipv4/netfilter/ip_fw_compat_masq.c
--- linux-2.4.0-test3-2/net/ipv4/netfilter/ip_fw_compat_masq.c	Thu Jun 29 01:26:09 2000
+++ working-2.4.0-test3-2/net/ipv4/netfilter/ip_fw_compat_masq.c	Tue Jul  4 17:29:24 2000
@@ -105,7 +105,7 @@
 	/* Wouldn't be here if not tracked already => masq'ed ICMP
            ping or error related to masq'd connection */
 	IP_NF_ASSERT(ct);
-	if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
+	if (ctinfo == IP_CT_RELATED) {
 		icmp_reply_translation(skb, ct, NF_IP_PRE_ROUTING,
 				       CTINFO2DIR(ctinfo));
 		icmp_reply_translation(skb, ct, NF_IP_POST_ROUTING,
diff -urN -X /tmp/file5l4Euc --minimal linux-2.4.0-test3-2/include/linux/netfilter_ipv4/ip_tables.h working-2.4.0-test3-2/include/linux/netfilter_ipv4/ip_tables.h
--- linux-2.4.0-test3-2/include/linux/netfilter_ipv4/ip_tables.h	Thu Jul  6 13:26:32 2000
+++ working-2.4.0-test3-2/include/linux/netfilter_ipv4/ip_tables.h	Fri Jul  7 18:42:41 2000
@@ -280,7 +280,7 @@
 	unsigned int size;
 
 	/* The entries. */
-	unsigned char entries[0];
+	struct ipt_entry entrytable[0];
 };
 
 /* Standard return verdict, or do jump. */
diff -urN -X /tmp/file5l4Euc --minimal linux-2.4.0-test3-2/include/linux/netfilter_ipv6/ip6_tables.h working-2.4.0-test3-2/include/linux/netfilter_ipv6/ip6_tables.h
--- linux-2.4.0-test3-2/include/linux/netfilter_ipv6/ip6_tables.h	Thu May 25 12:41:49 2000
+++ working-2.4.0-test3-2/include/linux/netfilter_ipv6/ip6_tables.h	Fri Jul  7 19:08:16 2000
@@ -286,7 +286,7 @@
 	unsigned int size;
 
 	/* The entries. */
-	unsigned char entries[0];
+	struct ip6t_entry entrytable[0];
 };
 
 /* Standard return verdict, or do jump. */
diff -urN -X /tmp/file5l4Euc --minimal linux-2.4.0-test3-2/net/ipv4/netfilter/ip_tables.c working-2.4.0-test3-2/net/ipv4/netfilter/ip_tables.c
--- linux-2.4.0-test3-2/net/ipv4/netfilter/ip_tables.c	Thu Jun 29 01:26:09 2000
+++ working-2.4.0-test3-2/net/ipv4/netfilter/ip_tables.c	Fri Jul  7 18:43:40 2000
@@ -1029,7 +1029,7 @@
 			 t->private->number);
 		if (entries->size == t->private->size)
 			ret = copy_entries_to_user(t->private->size,
-						   t, uptr->entries);
+						   t, uptr->entrytable);
 		else {
 			duprintf("get_entries: I've got %u not %u!\n",
 				 t->private->size,
diff -urN -X /tmp/file5l4Euc --minimal linux-2.4.0-test3-2/net/ipv6/netfilter/ip6_tables.c working-2.4.0-test3-2/net/ipv6/netfilter/ip6_tables.c
--- linux-2.4.0-test3-2/net/ipv6/netfilter/ip6_tables.c	Thu Jun 29 01:26:11 2000
+++ working-2.4.0-test3-2/net/ipv6/netfilter/ip6_tables.c	Fri Jul  7 19:15:15 2000
@@ -1075,7 +1075,7 @@
 			 t->private->number);
 		if (entries->size == t->private->size)
 			ret = copy_entries_to_user(t->private->size,
-						   t, uptr->entries);
+						   t, uptr->entrytable);
 		else {
 			duprintf("get_entries: I've got %u not %u!\n",
 				 t->private->size,
diff -urN -X /tmp/fileVB9oIz --minimal tmp/include/linux/netfilter_ipv4/ipt_REJECT.h working-2.4.0-test3-9/include/linux/netfilter_ipv4/ipt_REJECT.h
--- tmp/include/linux/netfilter_ipv4/ipt_REJECT.h	Tue Mar 28 04:35:56 2000
+++ working-2.4.0-test3-9/include/linux/netfilter_ipv4/ipt_REJECT.h	Tue Jul 11 17:36:54 2000
@@ -6,7 +6,10 @@
 	IPT_ICMP_HOST_UNREACHABLE,
 	IPT_ICMP_PROT_UNREACHABLE,
 	IPT_ICMP_PORT_UNREACHABLE,
-	IPT_ICMP_ECHOREPLY
+	IPT_ICMP_ECHOREPLY,
+	IPT_ICMP_NET_PROHIBITED,
+	IPT_ICMP_HOST_PROHIBITED,
+	IPT_TCP_RESET
 };
 
 struct ipt_reject_info {
diff -urN -X /tmp/fileVB9oIz --minimal tmp/net/core/netfilter.c working-2.4.0-test3-9/net/core/netfilter.c
--- tmp/net/core/netfilter.c	Fri Apr 14 10:19:57 2000
+++ working-2.4.0-test3-9/net/core/netfilter.c	Wed Jul 12 12:18:42 2000
@@ -261,11 +261,11 @@
 		if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING)
 				      | (1 << NF_IP_FORWARD)
 				      | (1 << NF_IP_POST_ROUTING))) {
-			/* Fragments will have no owners, but still
-                           may be local */
-			if (!(skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET))
-			    || skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
-						 | (1 << NF_IP_POST_ROUTING))){
+			/* Fragments, entunnelled packets, TCP RSTs
+                           generated by ipt_REJECT will have no
+                           owners, but still may be local */
+			if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
+					      | (1 << NF_IP_POST_ROUTING))){
 				printk("ip_finish_output:"
 				       " bad unowned skb = %p: ",skb);
 				debug_print_hooks_ip(skb->nf_debug);
diff -urN -X /tmp/fileVB9oIz --minimal tmp/net/ipv4/netfilter/ip_conntrack_core.c working-2.4.0-test3-9/net/ipv4/netfilter/ip_conntrack_core.c
--- tmp/net/ipv4/netfilter/ip_conntrack_core.c	Tue Jul 11 12:08:17 2000
+++ working-2.4.0-test3-9/net/ipv4/netfilter/ip_conntrack_core.c	Tue Jul 11 17:12:08 2000
@@ -551,6 +551,7 @@
 resolve_normal_ct(struct sk_buff *skb,
 		  struct ip_conntrack_protocol *proto,
 		  int *set_reply,
+		  unsigned int hooknum,
 		  enum ip_conntrack_info *ctinfo)
 {
 	struct ip_conntrack_tuple tuple;
@@ -573,6 +574,21 @@
 	if (DIRECTION(h) == IP_CT_DIR_REPLY) {
 		/* Reply on unconfirmed connection => unclassifiable */
 		if (!(h->ctrack->status & IPS_CONFIRMED)) {
+			/* Exception: local TCP RSTs (generated by
+                           REJECT target). */
+			if (hooknum == NF_IP_LOCAL_OUT
+			    && h->tuple.dst.protonum == IPPROTO_TCP) {
+				const struct tcphdr *tcph
+					= (const struct tcphdr *)
+					((u_int32_t *)skb->nh.iph
+					 + skb->nh.iph->ihl);
+				if (tcph->rst) {
+					*ctinfo	= IP_CT_ESTABLISHED
+						+ IP_CT_IS_REPLY;
+					*set_reply = 0;
+					goto set_skb;
+				}
+			}
 			DEBUGP("Reply on unconfirmed connection\n");
 			ip_conntrack_put(h->ctrack);
 			return NULL;
@@ -598,6 +614,7 @@
 		}
 		*set_reply = 0;
 	}
+ set_skb:
 	skb->nfct = &h->ctrack->infos[*ctinfo];
 	return h->ctrack;
 }
@@ -669,7 +686,7 @@
 	    && icmp_error_track(*pskb, &ctinfo, hooknum))
 		return NF_ACCEPT;
 
-	if (!(ct = resolve_normal_ct(*pskb, proto, &set_reply, &ctinfo)))
+	if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
 		/* Not valid part of a connection */
 		return NF_ACCEPT;
 
diff -urN -X /tmp/fileVB9oIz --minimal tmp/net/ipv4/netfilter/ip_conntrack_standalone.c working-2.4.0-test3-9/net/ipv4/netfilter/ip_conntrack_standalone.c
--- tmp/net/ipv4/netfilter/ip_conntrack_standalone.c	Fri Apr 28 08:43:15 2000
+++ working-2.4.0-test3-9/net/ipv4/netfilter/ip_conntrack_standalone.c	Tue Jul 11 17:12:08 2000
@@ -169,11 +169,15 @@
 			       const struct net_device *out,
 			       int (*okfn)(struct sk_buff *))
 {
-	/* We've seen it coming out the other side: confirm */
+	/* We've seen it coming out the other side: confirm (only if
+           new packet: REJECT can generate TCP RESET response, or ICMP
+           errors) */
 	if ((*pskb)->nfct) {
 		struct ip_conntrack *ct
 			= (struct ip_conntrack *)(*pskb)->nfct->master;
-		if (!(ct->status & IPS_CONFIRMED))
+		/* ctinfo is the index of the nfct inside the conntrack */
+		if ((*pskb)->nfct - ct->infos == IP_CT_NEW
+		    && !(ct->status & IPS_CONFIRMED))
 			ip_conntrack_confirm(ct);
 	}
 	return NF_ACCEPT;
@@ -191,7 +195,8 @@
 	if ((*pskb)->nfct) {
 		struct ip_conntrack *ct
 			= (struct ip_conntrack *)(*pskb)->nfct->master;
-		if (!(ct->status & IPS_CONFIRMED))
+		if ((*pskb)->nfct - ct->infos == IP_CT_NEW
+		    && !(ct->status & IPS_CONFIRMED))
 			ip_conntrack_confirm(ct);
 	}
 
diff -urN -X /tmp/fileVB9oIz --minimal tmp/net/ipv4/netfilter/ip_fw_compat.c working-2.4.0-test3-9/net/ipv4/netfilter/ip_fw_compat.c
--- tmp/net/ipv4/netfilter/ip_fw_compat.c	Tue Jul 11 12:08:17 2000
+++ working-2.4.0-test3-9/net/ipv4/netfilter/ip_fw_compat.c	Tue Jul 11 17:12:08 2000
@@ -71,7 +71,8 @@
 		struct ip_conntrack *ct
 			= (struct ip_conntrack *)skb->nfct->master;
 
-		if (!(ct->status & IPS_CONFIRMED))
+		if (skb->nfct - ct->infos == IP_CT_NEW
+		    && !(ct->status & IPS_CONFIRMED))
 			ip_conntrack_confirm(ct);
 	}
 }
diff -urN -X /tmp/fileVB9oIz --minimal tmp/net/ipv4/netfilter/ipt_REJECT.c working-2.4.0-test3-9/net/ipv4/netfilter/ipt_REJECT.c
--- tmp/net/ipv4/netfilter/ipt_REJECT.c	Tue Jun 27 14:52:47 2000
+++ working-2.4.0-test3-9/net/ipv4/netfilter/ipt_REJECT.c	Wed Jul 12 17:46:26 2000
@@ -7,6 +7,7 @@
 #include <linux/ip.h>
 #include <net/icmp.h>
 #include <net/ip.h>
+#include <net/tcp.h>
 struct in_device;
 #include <net/route.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
@@ -18,6 +19,113 @@
 #define DEBUGP(format, args...)
 #endif
 
+/* Send RST reply */
+static void send_reset(struct sk_buff *oldskb)
+{
+	struct sk_buff *nskb;
+	struct tcphdr *tcph;
+	struct rtable *rt;
+	unsigned int tcplen;
+	int needs_ack;
+
+	/* Clone skb (skb is about to be dropped, so we don't care) */
+	nskb = skb_clone(oldskb, GFP_ATOMIC);
+	if (!nskb)
+		return;
+
+	/* This packet will not be the same as the other: clear nf fields */
+	nf_conntrack_put(nskb->nfct);
+	nskb->nfct = NULL;
+	nskb->nfcache = 0;
+#ifdef CONFIG_NETFILTER_DEBUG
+	nskb->nf_debug = 0;
+#endif
+
+	/* IP header checks: fragment, too short. */
+	if (nskb->nh.iph->frag_off & htons(IP_OFFSET)
+	    || nskb->len < (nskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
+		goto free_nskb;
+
+	tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
+	tcplen = nskb->len - nskb->nh.iph->ihl*4;
+
+	/* Check checksum. */
+	if (tcp_v4_check(tcph, tcplen, nskb->nh.iph->saddr,
+			 nskb->nh.iph->daddr,
+			 csum_partial((char *)tcph, tcplen, 0)) != 0)
+		goto free_nskb;
+
+	/* No RST for RST. */
+	if (tcph->rst)
+		goto free_nskb;
+
+	nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
+	tcph->source = xchg(&tcph->dest, tcph->source);
+
+	/* Truncate to length (no data) */
+	tcph->doff = sizeof(struct tcphdr)/4;
+	skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
+
+	if (tcph->ack) {
+		needs_ack = 0;
+		tcph->seq = tcph->ack_seq;
+		tcph->ack_seq = 0;
+	} else {
+		needs_ack = 1;
+		tcph->seq = 0;
+		tcph->ack_seq = htonl(ntohl(tcph->seq) + tcph->syn + tcph->fin
+				      + tcplen - (tcph->doff<<2));
+	}
+
+	/* Reset flags */
+	((u_int8_t *)tcph)[13] = 0;
+	tcph->rst = 1;
+	if (needs_ack)
+		tcph->ack = 1;
+
+	tcph->window = 0;
+	tcph->urg_ptr = 0;
+
+	/* Adjust TCP checksum */
+	tcph->check = 0;
+	tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
+				   nskb->nh.iph->saddr,
+				   nskb->nh.iph->daddr,
+				   csum_partial((char *)tcph,
+						sizeof(struct tcphdr), 0));
+
+	/* Adjust IP TTL, DF */
+	nskb->nh.iph->ttl = MAXTTL;
+	/* Set DF, id = 0 */
+	nskb->nh.iph->frag_off = htons(IP_DF);
+	nskb->nh.iph->id = 0;
+
+	/* Adjust IP checksum */
+	nskb->nh.iph->check = 0;
+	nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 
+					   nskb->nh.iph->ihl);
+
+	/* Routing */
+	if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr,
+			    RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
+			    0) != 0)
+		goto free_nskb;
+
+	dst_release(nskb->dst);
+	nskb->dst = &rt->u.dst;
+
+	/* "Never happens" */
+	if (nskb->len > nskb->dst->pmtu)
+		goto free_nskb;
+
+	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
+		ip_finish_output);
+	return;
+
+ free_nskb:
+	kfree_skb(nskb);
+}
+
 static unsigned int reject(struct sk_buff **pskb,
 			   unsigned int hooknum,
 			   const struct net_device *in,
@@ -43,6 +151,12 @@
     	case IPT_ICMP_PORT_UNREACHABLE:
     		icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
     		break;
+    	case IPT_ICMP_NET_PROHIBITED:
+    		icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0);
+    		break;
+	case IPT_ICMP_HOST_PROHIBITED:
+    		icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0);
+    		break;
     	case IPT_ICMP_ECHOREPLY: {
 		struct icmphdr *icmph  = (struct icmphdr *)
 			((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl);
@@ -64,6 +178,9 @@
 		}
 	}
 	break;
+	case IPT_TCP_RESET:
+		send_reset(*pskb);
+		break;
 	}
 
 	return NF_DROP;
@@ -96,7 +213,7 @@
 
 	/* Only allow these for packet filtering. */
 	if (strcmp(tablename, "filter") != 0) {
-		DEBUGP("REJECT: bad table `%s'.\n", table);
+		DEBUGP("REJECT: bad table `%s'.\n", tablename);
 		return 0;
 	}
 	if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
@@ -116,6 +233,18 @@
 		/* Must contain ICMP match. */
 		if (IPT_MATCH_ITERATE(e, find_ping_match) == 0) {
 			DEBUGP("REJECT: ECHOREPLY illegal for non-ping\n");
+			return 0;
+		}
+	} else if (rejinfo->with == IPT_TCP_RESET) {
+		/* Must specify that it's a TCP packet */
+		if (e->ip.proto != IPPROTO_TCP
+		    || (e->ip.invflags & IPT_INV_PROTO)) {
+			DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n");
+			return 0;
+		}
+		/* Only for local input.  Rest is too dangerous. */
+		if ((hook_mask & ~(1 << NF_IP_LOCAL_IN)) != 0) {
+			DEBUGP("REJECT: TCP_RESET only from INPUT\n");
 			return 0;
 		}
 	}
diff -urN -X /tmp/fileCRGgIa --minimal tmp/include/linux/netfilter_ipv4/ip_nat_core.h working-2.4.0-test4/include/linux/netfilter_ipv4/ip_nat_core.h
--- tmp/include/linux/netfilter_ipv4/ip_nat_core.h	Sat Apr 15 03:05:39 2000
+++ working-2.4.0-test4/include/linux/netfilter_ipv4/ip_nat_core.h	Fri Jul 14 15:12:09 2000
@@ -16,10 +16,10 @@
 
 extern struct list_head protos;
 
-extern void icmp_reply_translation(struct sk_buff *skb,
-				   struct ip_conntrack *conntrack,
-				   unsigned int hooknum,
-				   int dir);
+extern unsigned int icmp_reply_translation(struct sk_buff *skb,
+					   struct ip_conntrack *conntrack,
+					   unsigned int hooknum,
+					   int dir);
 
 extern void replace_in_hashes(struct ip_conntrack *conntrack,
 			      struct ip_nat_info *info);
diff -urN -X /tmp/fileCRGgIa --minimal tmp/net/ipv4/netfilter/ip_nat_core.c working-2.4.0-test4/net/ipv4/netfilter/ip_nat_core.c
--- tmp/net/ipv4/netfilter/ip_nat_core.c	Tue Jul 11 12:08:17 2000
+++ working-2.4.0-test4/net/ipv4/netfilter/ip_nat_core.c	Fri Jul 14 17:14:13 2000
@@ -735,7 +735,7 @@
 	} else return NF_ACCEPT;
 }
 
-void
+unsigned int
 icmp_reply_translation(struct sk_buff *skb,
 		       struct ip_conntrack *conntrack,
 		       unsigned int hooknum,
@@ -749,6 +749,22 @@
 	struct ip_nat_info *info = &conntrack->nat.info;
 
 	IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr));
+	/* Must be RELATED */
+	IP_NF_ASSERT(skb->nfct - (struct ip_conntrack *)skb->nfct->master
+		     == IP_CT_RELATED
+		     || skb->nfct - (struct ip_conntrack *)skb->nfct->master
+		     == IP_CT_RELATED+IP_CT_IS_REPLY);
+
+	/* Redirects on non-null nats must be dropped, else they'll
+           start talking to each other without our translation, and be
+           confused... --RR */
+	if (hdr->type == ICMP_REDIRECT) {
+		/* Don't care about races here. */
+		if (info->initialized
+		    != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
+		    || info->num_manips != 0)
+			return NF_DROP;
+	}
 
 	DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
 	       skb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
@@ -810,6 +826,8 @@
 	hdr->checksum = 0;
 	hdr->checksum = ip_compute_csum((unsigned char *)hdr,
 					sizeof(*hdr) + datalen);
+
+	return NF_ACCEPT;
 }
 
 int ip_nat_helper_register(struct ip_nat_helper *me)
diff -urN -X /tmp/fileCRGgIa --minimal tmp/net/ipv4/netfilter/ip_nat_standalone.c working-2.4.0-test4/net/ipv4/netfilter/ip_nat_standalone.c
--- tmp/net/ipv4/netfilter/ip_nat_standalone.c	Tue Jul 11 12:08:17 2000
+++ working-2.4.0-test4/net/ipv4/netfilter/ip_nat_standalone.c	Fri Jul 14 15:05:45 2000
@@ -84,9 +84,8 @@
 	case IP_CT_RELATED:
 	case IP_CT_RELATED+IP_CT_IS_REPLY:
 		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
-			icmp_reply_translation(*pskb, ct, hooknum,
-					       CTINFO2DIR(ctinfo));
-			return NF_ACCEPT;
+			return icmp_reply_translation(*pskb, ct, hooknum,
+						      CTINFO2DIR(ctinfo));
 		}
 		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
 	case IP_CT_NEW:
diff -urN linux-2.4.0-test4-pre6/net/ipv4/netfilter/ip_queue.c linux/net/ipv4/netfilter/ip_queue.c
--- linux-2.4.0-test4-pre6/net/ipv4/netfilter/ip_queue.c	Thu Jul 13 23:31:22 2000
+++ linux/net/ipv4/netfilter/ip_queue.c	Thu Jul 13 23:35:38 2000
@@ -244,7 +244,7 @@
 {
 	ipq_queue_element_t *e;
 
-	if (v->value < 0 || v->value > NF_MAX_VERDICT)
+	if (v->value > NF_MAX_VERDICT)
 		return -EINVAL;
 	e = ipq_dequeue(q, id_cmp, v->id);
 	if (e == NULL)
@@ -309,10 +309,9 @@
 		if (e->info->indev->ifindex == ifindex)
 			return 1;
 	if (e->info->outdev)
-		if (e->info->outdev->ifindex == ifindex);
+		if (e->info->outdev->ifindex == ifindex)
 			return 1;
 	return 0;
-	
 }
 
 /* Drop any queued packets associated with device ifindex */

--
Hacking time.