diff -Nru linux-2.4.20/Documentation/Configure.help linux-2.4.20-pom2patch/Documentation/Configure.help
--- linux-2.4.20/Documentation/Configure.help	2003-05-02 12:56:58.000000000 -0500
+++ linux-2.4.20-pom2patch/Documentation/Configure.help	2003-05-02 12:57:00.000000000 -0500
@@ -3118,6 +3118,24 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
 
+ROUTE target support
+CONFIG_IP_NF_TARGET_ROUTE
+  This option adds a `ROUTE' target, which enables you to setup unusual
+  routes not supported by the standard kernel routing table.
+  For example, the ROUTE lets you directly route a received packet through 
+  an interface or towards a host, even if the regular destination of the 
+  packet is the router itself. The ROUTE target is also able to change the 
+  incoming interface of a packet.
+
+  This target does never modify the packet and is a final target.
+  It has to be used inside the mangle table.
+
+  
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  The module will be called ipt_ROUTE.o.
+  If unsure, say `N'.
+
+
 LOG target support
 CONFIG_IP_NF_TARGET_LOG
   This option adds a `LOG' target, which allows you to create rules in
diff -Nru linux-2.4.20/include/linux/netfilter_ipv4/ipt_ROUTE.h linux-2.4.20-pom2patch/include/linux/netfilter_ipv4/ipt_ROUTE.h
--- linux-2.4.20/include/linux/netfilter_ipv4/ipt_ROUTE.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.4.20-pom2patch/include/linux/netfilter_ipv4/ipt_ROUTE.h	2003-05-02 12:57:00.000000000 -0500
@@ -0,0 +1,18 @@
+/* Header file for iptables ipt_ROUTE target
+ *
+ * (C) 2002 by Cdric de Launois <delaunois@info.ucl.ac.be>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ */
+#ifndef _IPT_ROUTE_H_target
+#define _IPT_ROUTE_H_target
+
+#define IPT_ROUTE_IFNAMSIZ 16
+
+struct ipt_route_target_info {
+	char oif[IPT_ROUTE_IFNAMSIZ];
+	char iif[IPT_ROUTE_IFNAMSIZ];
+	unsigned int gw;
+};
+
+#endif /*_IPT_ROUTE_H_target*/
diff -Nru linux-2.4.20/net/ipv4/netfilter/Config.in linux-2.4.20-pom2patch/net/ipv4/netfilter/Config.in
--- linux-2.4.20/net/ipv4/netfilter/Config.in	2003-05-02 12:56:58.000000000 -0500
+++ linux-2.4.20-pom2patch/net/ipv4/netfilter/Config.in	2003-05-02 12:57:00.000000000 -0500
@@ -116,6 +116,7 @@
     dep_tristate '    CLASSIFY target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_CLASSIFY $CONFIG_IP_NF_FILTER
   fi
   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  ROUTE target support' CONFIG_IP_NF_TARGET_ROUTE $CONFIG_IP_NF_IPTABLES
   if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then
     dep_tristate '  CONNMARK target support' CONFIG_IP_NF_TARGET_CONNMARK $CONFIG_IP_NF_IPTABLES
   fi
diff -Nru linux-2.4.20/net/ipv4/netfilter/Makefile linux-2.4.20-pom2patch/net/ipv4/netfilter/Makefile
--- linux-2.4.20/net/ipv4/netfilter/Makefile	2003-05-02 12:56:58.000000000 -0500
+++ linux-2.4.20-pom2patch/net/ipv4/netfilter/Makefile	2003-05-02 12:57:01.000000000 -0500
@@ -110,6 +110,7 @@
 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o
 obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
diff -Nru linux-2.4.20/net/ipv4/netfilter/ipt_ROUTE.c linux-2.4.20-pom2patch/net/ipv4/netfilter/ipt_ROUTE.c
--- linux-2.4.20/net/ipv4/netfilter/ipt_ROUTE.c	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.4.20-pom2patch/net/ipv4/netfilter/ipt_ROUTE.c	2003-05-02 12:57:00.000000000 -0500
@@ -0,0 +1,359 @@
+/*
+ * This implements the ROUTE target, which enables you to setup unusual
+ * routes not supported by the standard kernel routing table.
+ *
+ * Copyright (C) 2002 Cedric de Launois <delaunois@info.ucl.ac.be>
+ *
+ * v 1.6 2003/02/26
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ROUTE.h>
+#include <linux/netdevice.h>
+#include <linux/route.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include <net/icmp.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+
+/* Try to route the packet according to the routing keys specified in
+ * route_info. Keys are :
+ *  - ifindex : 
+ *      0 if no oif prefered, 
+ *      otherwise set to the index of the desired oif
+ *  - route_info->gw :
+ *      0 if no gateway specified,
+ *      otherwise set to the next host to which the pkt must be routed
+ * If success, skb->dev is the output device to which the packet must 
+ * be sent and skb->dst is not NULL
+ *
+ * RETURN: -1 if an error occured
+ *          1 if the packet was succesfully routed to the 
+ *            destination desired
+ *          0 if the kernel routing table could not route the packet
+ *            according to the keys specified
+ */
+static int route(struct sk_buff *skb,
+		 unsigned int ifindex,
+		 const struct ipt_route_target_info *route_info)
+{
+	int err;
+	struct rtable *rt;
+	struct iphdr *iph = skb->nh.iph;
+	struct rt_key key = { 
+		dst:iph->daddr,
+		src:0,
+		oif:ifindex, 
+		tos:RT_TOS(iph->tos) 
+	};
+	
+	/* The destination address may be overloaded by the target */
+	if (route_info->gw)
+		key.dst = route_info->gw;
+	
+	/* Trying to route the packet with the standard routing table. */
+	if ((err = ip_route_output_key(&rt, &key))) {
+		DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err);
+		return -1;
+	}
+	
+	/* Drop old route. */
+	dst_release(skb->dst);
+	skb->dst = NULL;
+
+	/* Success if no oif specified or if the oif correspond to the 
+	 * one desired */
+	if (!ifindex || rt->u.dst.dev->ifindex == ifindex) {
+		/* Drop old route. */
+		skb->dst = &rt->u.dst;
+		skb->dev = skb->dst->dev;
+		return 1;
+	}
+	
+	/* The interface selected by the routing table is not the one
+	 * specified by the user. This may happen because the dst address
+	 * is one of our own addresses.
+	 */
+	DEBUGP("ipt_ROUTE: failed to route as desired (oif: %i)", 
+	       rt->u.dst.dev->ifindex);
+	
+	return 0;
+}
+
+
+/* Stolen from ip_finish_output2
+ * PRE : skb->dev is set to the device we are leaving by
+ *       skb->dst is not NULL
+ * POST: the packet is sent with the link layer header pushed
+ *       the packet is destroyed
+ */
+static void ip_direct_send(struct sk_buff *skb)
+{
+	struct dst_entry *dst = skb->dst;
+	struct hh_cache *hh = dst->hh;
+
+	if (hh) {
+		read_lock_bh(&hh->hh_lock);
+		memcpy(skb->data - 16, hh->hh_data, 16);
+		read_unlock_bh(&hh->hh_lock);
+		skb_push(skb, hh->hh_len);
+		hh->hh_output(skb);
+	} else if (dst->neighbour)
+		dst->neighbour->output(skb);
+	else {
+		if (net_ratelimit())
+			DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n");
+		kfree_skb(skb);
+	}
+}
+
+
+/* PRE : skb->dev is set to the device we are leaving by
+ * POST: - the packet is directly sent to the skb->dev device, without 
+ *         pushing the link layer header.
+ *       - the packet is destroyed
+ */
+static inline int dev_direct_send(struct sk_buff *skb)
+{
+	return dev_queue_xmit(skb);
+}
+
+
+static unsigned int route_oif(const struct ipt_route_target_info *route_info,
+			      struct sk_buff *skb) 
+{
+	int err;
+	unsigned int ifindex = 0;
+	struct net_device *dev_out = NULL;
+
+	/* The user set the interface name to use.
+	 * Getting the current interface index.
+	 */
+	if ((dev_out = dev_get_by_name(route_info->oif)))
+		ifindex = dev_out->ifindex;
+	else 
+		/* Unknown interface name : packet dropped */
+		return NF_DROP;
+	
+	DEBUGP(KERN_DEBUG "oif index of %s is %i\n", route_info->oif, ifindex);
+
+
+	/* Trying the standard way of routing packets */
+	err = route(skb, ifindex, route_info);
+	if (err==1) {
+		DEBUGP(KERN_DEBUG "ROUTE oif ok, skb->dev->index=%i\n",
+		       skb->dev->ifindex);
+
+		dev_put(dev_out);
+		ip_direct_send(skb);
+		return NF_STOLEN;
+	}
+
+	if (err) {
+		dev_put(dev_out);
+		return NF_DROP;
+	}
+
+	/* Failed to send to oif. Trying the hard way */
+
+	DEBUGP(KERN_DEBUG "HARD ROUTING\n");
+
+	/* We have to force the use of an interface.
+	 * This interface must be a tunnel interface since
+	 * otherwise we can't guess the hw address for
+	 * the packet. For a tunnel interface, no hw address
+	 * is needed.
+	 */
+	if ((dev_out->type != ARPHRD_TUNNEL)
+	    && (dev_out->type != ARPHRD_IPGRE)) {
+		DEBUGP("ipt_ROUTE: can't guess the hw addr !\n");
+		dev_put(dev_out);
+		return NF_DROP;
+	}
+	
+	/* Send the packet. This will also free skb
+	 * Do not go through the POST_ROUTING hook because 
+	 * skb->dst is not set and because it will probably
+	 * get confused by the destination IP address.
+	 */
+	skb->dev = dev_out;
+	dev_direct_send(skb);
+	dev_put(dev_out);
+	return NF_STOLEN;
+}
+
+
+static unsigned int route_iif(const struct ipt_route_target_info *route_info,
+			      struct sk_buff *skb) 
+{
+	struct net_device *dev_out = NULL;
+	unsigned int ifindex = 0;
+
+	/* Getting the current interface index. */
+	if ((dev_out = dev_get_by_name(route_info->iif)))
+		ifindex = dev_out->ifindex;
+	else 
+		/* Unknown interface name : packet dropped */
+		return NF_DROP;
+
+	DEBUGP(KERN_DEBUG "iif index of %s is %i\n", route_info->iif, ifindex);
+
+	skb->dev = dev_out;
+	dst_release(skb->dst);
+	skb->dst = NULL;
+		
+	netif_rx(skb);
+
+	return NF_STOLEN;
+}
+
+
+static unsigned int route_gw(const struct ipt_route_target_info *route_info,
+			     struct sk_buff *skb) 
+{
+	if (route(skb, 0, route_info)!=1)
+		return NF_DROP;
+
+	DEBUGP(KERN_DEBUG "ROUTE gw ok, skb->dev->index=%i\n",
+	       skb->dev->ifindex);
+
+	ip_direct_send(skb);
+
+	return NF_STOLEN;
+}
+
+
+static unsigned int ipt_route_target(struct sk_buff **pskb,
+				     unsigned int hooknum,
+				     const struct net_device *in,
+				     const struct net_device *out,
+				     const void *targinfo,
+				     void *userinfo)
+{
+	const struct ipt_route_target_info *route_info = targinfo;
+	struct sk_buff *skb = *pskb;
+
+	/* If we are at PREROUTING or INPUT hook
+	 * the TTL isn't decreased by the IP stack
+	 */
+	if (hooknum == NF_IP_PRE_ROUTING ||
+	    hooknum == NF_IP_LOCAL_IN) {
+
+		struct iphdr *iph = skb->nh.iph;
+
+		if (iph->ttl <= 1) {
+			struct rtable *rt;
+
+			if (ip_route_output(&rt, iph->saddr, iph->daddr,
+					    RT_TOS(iph->tos) | RTO_CONN,
+					    0)) {
+				return NF_DROP;
+			}
+
+			if (skb->dev == rt->u.dst.dev) {
+				/* Drop old route. */
+				dst_release(skb->dst);
+				skb->dst = &rt->u.dst;
+
+				/* this will traverse normal stack, and 
+				 * thus call conntrack on the icmp packet */
+				icmp_send(skb, ICMP_TIME_EXCEEDED, 
+					  ICMP_EXC_TTL, 0);
+			}
+
+			return NF_DROP;
+		}
+
+		ip_decrease_ttl(iph);
+	}
+
+	/* Tell conntrack to forget this packet since it may get confused 
+	 * when a packet is leaving with dst address == our address.
+	 * Good idea ? Dunno. Need advice.
+	 */
+	nf_conntrack_put(skb->nfct);
+	skb->nfct = NULL;
+	skb->nfcache = 0;
+#ifdef CONFIG_NETFILTER_DEBUG
+	skb->nf_debug = 0;
+#endif
+
+	if (route_info->oif[0]) 
+		return route_oif(route_info, *pskb);
+	
+	if (route_info->iif[0]) 
+		return route_iif(route_info, *pskb);
+
+	if (route_info->gw) 
+		return route_gw(route_info, *pskb);
+
+	DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
+	return NF_ACCEPT;
+}
+
+
+static int ipt_route_checkentry(const char *tablename,
+				const struct ipt_entry *e,
+				void *targinfo,
+				unsigned int targinfosize,
+				unsigned int hook_mask)
+{
+	if (strcmp(tablename, "mangle") != 0) {
+		printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n",
+		       tablename);
+		return 0;
+	}
+
+	if (hook_mask & ~(  (1 << NF_IP_PRE_ROUTING)
+			    | (1 << NF_IP_LOCAL_IN)
+			    | (1 << NF_IP_FORWARD)
+			    | (1 << NF_IP_LOCAL_OUT)
+			    | (1 << NF_IP_POST_ROUTING))) {
+		printk("ipt_ROUTE: bad hook\n");
+		return 0;
+	}
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) {
+		printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       IPT_ALIGN(sizeof(struct ipt_route_target_info)));
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static struct ipt_target ipt_route_reg
+= { { NULL, NULL }, "ROUTE", ipt_route_target, ipt_route_checkentry, NULL,
+    THIS_MODULE };
+
+
+static int __init init(void)
+{
+	if (ipt_register_target(&ipt_route_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_route_reg);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
