diff -urN linux-2.6.23.17-orig/include/linux/netfilter/xt_tcpudp.h linux-2.6.23.17/include/linux/netfilter/xt_tcpudp.h
--- linux-2.6.23.17-orig/include/linux/netfilter/xt_tcpudp.h	2008-02-26 08:14:28.000000000 +0800
+++ linux-2.6.23.17/include/linux/netfilter/xt_tcpudp.h	2011-01-12 10:12:20.000000000 +0800
@@ -32,5 +32,23 @@
 #define XT_UDP_INV_DSTPT	0x02	/* Invert the sense of dest ports. */
 #define XT_UDP_INV_MASK	0x03	/* All possible flags. */
 
+/* Service matching stuff */
+struct xt_service
+{
+	u_int32_t flg_service;
+	u_int16_t spts[2];			/* Source port range. */
+	u_int16_t dpts[2];			/* Destination port range. */
+	u_int8_t option;			/* TCP Option iff non-zero*/
+	u_int8_t flg_mask;			/* TCP flags mask byte */
+	u_int8_t flg_cmp;			/* TCP flags compare byte */
+	u_int8_t invflags;			/* Inverse flags */
+};
+
+/* Values for "inv" field in struct ipt_tcp. */
+#define XT_SERVICE_ICMP	0x01
+#define XT_SERVICE_IGMP	0x02
+#define XT_SERVICE_TCP	0x04
+#define XT_SERVICE_UDP	0x08
+#define XT_SERVICE_MASK	0x0F
 
 #endif
diff -urN linux-2.6.23.17-orig/include/linux/netfilter.h linux-2.6.23.17/include/linux/netfilter.h
--- linux-2.6.23.17-orig/include/linux/netfilter.h	2008-02-26 08:14:28.000000000 +0800
+++ linux-2.6.23.17/include/linux/netfilter.h	2011-01-17 14:15:02.000000000 +0800
@@ -26,10 +26,14 @@
 #define NF_VERDICT_MASK 0x0000ffff
 #define NF_VERDICT_BITS 16
 
+#define NF_WCF_QMASK 0xffffff00
+#define NF_WCF_FLAG_BIT 8
+
 #define NF_VERDICT_QMASK 0xffff0000
 #define NF_VERDICT_QBITS 16
 
 #define NF_QUEUE_NR(x) (((x << NF_VERDICT_QBITS) & NF_VERDICT_QMASK) | NF_QUEUE)
+#define NF_QUEUE_NR_WCF(x, y) ((((x << NF_VERDICT_QBITS) | (y << NF_WCF_FLAG_BIT)) & NF_WCF_QMASK) | NF_QUEUE)
 
 /* only for userspace compatibility */
 #ifndef __KERNEL__
diff -urN linux-2.6.23.17-orig/include/linux/netfilter_ipv4/ip_tables.h linux-2.6.23.17/include/linux/netfilter_ipv4/ip_tables.h
--- linux-2.6.23.17-orig/include/linux/netfilter_ipv4/ip_tables.h	2008-02-26 08:14:28.000000000 +0800
+++ linux-2.6.23.17/include/linux/netfilter_ipv4/ip_tables.h	2011-01-12 10:50:10.000000000 +0800
@@ -61,7 +61,8 @@
 /* Values for "flag" field in struct ipt_ip (general ip structure). */
 #define IPT_F_FRAG		0x01	/* Set if rule is a fragment rule */
 #define IPT_F_GOTO		0x02	/* Set if jump is a goto */
-#define IPT_F_MASK		0x03	/* All possible flag bits mask. */
+#define IPT_F_UNEN		0x04	/* Set if disable this rule */
+#define IPT_F_MASK		0x07	/* All possible flag bits mask. */
 
 /* Values for "inv" field in struct ipt_ip. */
 #define IPT_INV_VIA_IN		0x01	/* Invert the sense of IN IFACE. */
diff -urN linux-2.6.23.17-orig/include/linux/skbuff.h linux-2.6.23.17/include/linux/skbuff.h
--- linux-2.6.23.17-orig/include/linux/skbuff.h	2011-01-18 13:26:38.000000000 +0800
+++ linux-2.6.23.17/include/linux/skbuff.h	2011-01-18 09:35:12.000000000 +0800
@@ -295,10 +295,7 @@
 	struct nf_conntrack	*nfct;
 	struct sk_buff		*nfct_reasm;
 #endif
-#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-	unsigned char		imq_flags;
-	struct nf_info		*nf_info;
-#endif
+
 #ifdef CONFIG_BRIDGE_NETFILTER
 	struct nf_bridge_info	*nf_bridge;
 #endif
@@ -333,6 +330,11 @@
 				*data;
 	unsigned int		truesize;
 	atomic_t		users;
+#if 1 //defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
+	unsigned char		imq_flags;
+	struct nf_info		*nf_info;
+#endif
+
 };
 
 #ifdef __KERNEL__
diff -urN linux-2.6.23.17-orig/kernel/Makefile linux-2.6.23.17/kernel/Makefile
--- linux-2.6.23.17-orig/kernel/Makefile	2011-01-13 16:54:33.000000000 +0800
+++ linux-2.6.23.17/kernel/Makefile	2011-01-13 18:07:10.000000000 +0800
@@ -3,7 +3,7 @@
 #
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
-	    exit.o itimer.o time.o softirq.o resource.o \
+	    exit.o itimer.o time.o softirq.o resource.o ksocket.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o user_namespace.o \
 	    signal.o sys.o kmod.o workqueue.o pid.o \
 	    rcupdate.o extable.o params.o posix-timers.o \
diff -urN linux-2.6.23.17-orig/net/ipv4/ip_output.c linux-2.6.23.17/net/ipv4/ip_output.c
--- linux-2.6.23.17-orig/net/ipv4/ip_output.c	2008-02-26 08:14:28.000000000 +0800
+++ linux-2.6.23.17/net/ipv4/ip_output.c	2011-01-12 13:07:03.000000000 +0800
@@ -202,7 +202,7 @@
 	       skb->dst->dev->mtu : dst_mtu(skb->dst);
 }
 
-static inline int ip_finish_output(struct sk_buff *skb)
+int ip_finish_output(struct sk_buff *skb)
 {
 #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
 	/* Policy lookup after SNAT yielded a new policy */
@@ -1410,3 +1410,4 @@
 EXPORT_SYMBOL(ip_generic_getfrag);
 EXPORT_SYMBOL(ip_queue_xmit);
 EXPORT_SYMBOL(ip_send_check);
+EXPORT_SYMBOL(ip_finish_output);
diff -urN linux-2.6.23.17-orig/net/ipv4/netfilter/ip_tables.c linux-2.6.23.17/net/ipv4/netfilter/ip_tables.c
--- linux-2.6.23.17-orig/net/ipv4/netfilter/ip_tables.c	2008-02-26 08:14:28.000000000 +0800
+++ linux-2.6.23.17/net/ipv4/netfilter/ip_tables.c	2011-01-11 16:35:22.000000000 +0800
@@ -86,6 +86,10 @@
 
 #define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg))
 
+	if ((ipinfo->flags&IPT_F_UNEN)) {
+		return 0;
+	}
+
 	if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
 		  IPT_INV_SRCIP)
 	    || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
diff -urN linux-2.6.23.17-orig/net/netfilter/Kconfig linux-2.6.23.17/net/netfilter/Kconfig
--- linux-2.6.23.17-orig/net/netfilter/Kconfig	2011-01-12 14:12:31.000000000 +0800
+++ linux-2.6.23.17/net/netfilter/Kconfig	2011-01-13 17:13:23.000000000 +0800
@@ -354,6 +354,14 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_TARGET_WEBCATEGORY
+	tristate '"WEBCATEGORY" target Support'
+	depends on NETFILTER_XTABLES
+	help
+	  This module is used to enqueue packets for webcategory check.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_TARGET_NFLOG
 	tristate '"NFLOG" target support'
 	depends on NETFILTER_XTABLES
diff -urN linux-2.6.23.17-orig/net/netfilter/Makefile linux-2.6.23.17/net/netfilter/Makefile
--- linux-2.6.23.17-orig/net/netfilter/Makefile	2011-01-14 15:08:20.000000000 +0800
+++ linux-2.6.23.17/net/netfilter/Makefile	2011-01-17 13:41:18.000000000 +0800
@@ -44,6 +44,7 @@
 obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_WEBCATEGORY) += xt_WEBCATEGORY.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
diff -urN linux-2.6.23.17-orig/net/netfilter/core.c linux-2.6.23.17/net/netfilter/core.c
--- linux-2.6.23.17-orig/net/netfilter/core.c	2011-01-18 13:27:53.000000000 +0800
+++ linux-2.6.23.17/net/netfilter/core.c	2011-01-18 11:53:01.000000000 +0800
@@ -182,10 +182,12 @@
 	} else if (verdict == NF_DROP) {
 		kfree_skb(*pskb);
 		ret = -EPERM;
-	} else if ((verdict & NF_VERDICT_MASK)  == NF_QUEUE) {
+//	} else if ((verdict & NF_VERDICT_MASK)  == NF_QUEUE) {
+	} else if ((verdict & ~NF_WCF_QMASK)  == NF_QUEUE) {
 		NFDEBUG("nf_hook: Verdict = QUEUE.\n");
 		if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn,
-			      verdict >> NF_VERDICT_BITS))
+//			      verdict >> NF_VERDICT_BITS))
+			      verdict >> NF_WCF_FLAG_BIT))
 			goto next_hook;
 	}
 unlock:
diff -urN linux-2.6.23.17-orig/net/netfilter/xt_tcpudp.c linux-2.6.23.17/net/netfilter/xt_tcpudp.c
--- linux-2.6.23.17-orig/net/netfilter/xt_tcpudp.c	2008-02-26 08:14:28.000000000 +0800
+++ linux-2.6.23.17/net/netfilter/xt_tcpudp.c	2011-01-14 13:21:42.000000000 +0800
@@ -194,6 +194,57 @@
 	return !(udpinfo->invflags & ~XT_UDP_INV_MASK);
 }
 
+static int
+service_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)
+{
+	const struct xt_service *serviceinfo = matchinfo;
+	struct iphdr *ip = ip_hdr(skb);
+	
+	if (ip->protocol == IPPROTO_TCP && (serviceinfo->flg_service & XT_SERVICE_TCP)) {
+		struct xt_tcp tcpinfo;
+		memcpy(tcpinfo.spts, serviceinfo->spts, sizeof(u_int16_t)*2);
+		memcpy(tcpinfo.dpts, serviceinfo->dpts, sizeof(u_int16_t)*2);
+		tcpinfo.option = serviceinfo->option;
+		tcpinfo.flg_cmp = serviceinfo->flg_cmp;
+		tcpinfo.flg_mask = serviceinfo->flg_mask;
+		tcpinfo.invflags = serviceinfo->invflags;
+		return tcp_match(skb, in, out, match, &tcpinfo, offset, protoff, hotdrop);
+	} else if (ip->protocol == IPPROTO_UDP && (serviceinfo->flg_service & XT_SERVICE_UDP)) {
+		struct xt_udp udpinfo;
+		memcpy(udpinfo.spts, serviceinfo->spts, sizeof(u_int16_t)*2);
+		memcpy(udpinfo.dpts, serviceinfo->dpts, sizeof(u_int16_t)*2);
+		udpinfo.invflags = serviceinfo->invflags;
+		return udp_match(skb, in, out, match, &udpinfo, offset, protoff, hotdrop);
+	} else if (ip->protocol == IPPROTO_IGMP && (serviceinfo->flg_service & XT_SERVICE_IGMP)) {
+		return 1;
+	} else if (ip->protocol == IPPROTO_ICMP && (serviceinfo->flg_service & XT_SERVICE_ICMP)) {
+		return 1;		
+	} else {
+		return 0;
+	}
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+service_checkentry(const char *tablename,
+	       const void *info,
+	       const struct xt_match *match,
+	       void *matchinfo,
+	       unsigned int hook_mask)
+{
+	const struct xt_service *serviceinfo = matchinfo;
+
+	/* Must specify no unknown invflags */
+	return !(serviceinfo->invflags & ~XT_UDP_INV_MASK) && !(serviceinfo->flg_service & ~XT_SERVICE_MASK);
+}
+
 static struct xt_match xt_tcpudp_match[] __read_mostly = {
 	{
 		.name		= "tcp",
@@ -249,6 +300,22 @@
 		.proto		= IPPROTO_UDPLITE,
 		.me		= THIS_MODULE,
 	},
+	{
+		.name		= "service",
+		.family		= AF_INET,
+		.checkentry	= service_checkentry,
+		.match		= service_match,
+		.matchsize	= sizeof(struct xt_service),
+		.me		= THIS_MODULE,
+	},
+	{
+		.name		= "service",
+		.family		= AF_INET6,
+		.checkentry	= service_checkentry,
+		.match		= service_match,
+		.matchsize	= sizeof(struct xt_service),
+		.me		= THIS_MODULE,
+	},
 };
 
 static int __init xt_tcpudp_init(void)
