All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ROUTE target : update to pom-ng + new version for kernel 2.6.x
@ 2004-04-21  8:16 Cedric de Launois
  2004-04-24 23:03 ` Patrick McHardy
  0 siblings, 1 reply; 6+ messages in thread
From: Cedric de Launois @ 2004-04-21  8:16 UTC (permalink / raw)
  To: Netfilter Development Mailinglist

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

Hi,

Here is a patch to convert the ROUTE target to the new pom-ng.
This patch also contains a corrected version of the ROUTE target
for kernels 2.6.x.

Other fixes for the ROUTE target will follow.

The patch is against the current cvs tree.

Cedric


[-- Attachment #2: ROUTE.pom-ng.patch --]
[-- Type: text/x-patch, Size: 64672 bytes --]

diff -Nru ROUTE.orig/info ROUTE/info
--- ROUTE.orig/info	2004-02-20 00:11:50.000000000 +0100
+++ ROUTE/info	2004-03-08 14:19:22.000000000 +0100
@@ -1,4 +1,5 @@
 Author: Cédric de Launois <delaunois@info.ucl.ac.be>
 Status: Experimental
 Repository: extra
-Requires: linux < 2.6.0
+Recompile: netfilter
+Recompile: iptables
diff -Nru ROUTE.orig/linux/Documentation/Configure.help.ladd ROUTE/linux/Documentation/Configure.help.ladd
--- ROUTE.orig/linux/Documentation/Configure.help.ladd	2004-02-19 12:30:08.000000000 +0100
+++ ROUTE/linux/Documentation/Configure.help.ladd	1970-01-01 01:00:00.000000000 +0100
@@ -1,16 +0,0 @@
-CONFIG_IP_NF_TARGET_MARK
-ROUTE target support
-CONFIG_IP_NF_TARGET_ROUTE
-  This option adds a `ROUTE' target, which enables you to setup unusual
-  routes. For example, the ROUTE lets you 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.
-
-  The target can be or not 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'.
-
diff -Nru ROUTE.orig/linux/Documentation/Configure.help.ladd_2 ROUTE/linux/Documentation/Configure.help.ladd_2
--- ROUTE.orig/linux/Documentation/Configure.help.ladd_2	2004-03-05 10:30:26.000000000 +0100
+++ ROUTE/linux/Documentation/Configure.help.ladd_2	1970-01-01 01:00:00.000000000 +0100
@@ -1,12 +0,0 @@
-CONFIG_IP6_NF_TARGET_MARK
-ROUTE target support
-CONFIG_IP6_NF_TARGET_ROUTE
-  This option adds a `ROUTE' target, which enables you to setup unusual
-  routes. The ROUTE target is also able to change the incoming interface
-  of a packet.
-
-  The target can be or not a final target. It has to be used inside the 
-  mangle table.
-  
-  Not working as a module.
-
diff -Nru ROUTE.orig/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h ROUTE/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h
--- ROUTE.orig/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h	2003-12-18 19:47:54.000000000 +0100
+++ ROUTE/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,22 +0,0 @@
-/* Header file for iptables ipt_ROUTE target
- *
- * (C) 2002 by Cédric 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];      /* Output Interface Name */
-	char      iif[IPT_ROUTE_IFNAMSIZ];      /* Input Interface Name  */
-	u_int32_t gw;                           /* IP address of gateway */
-	u_int8_t  flags;
-};
-
-/* Values for "flags" field */
-#define IPT_ROUTE_CONTINUE        0x01
-
-#endif /*_IPT_ROUTE_H_target*/
diff -Nru ROUTE.orig/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h ROUTE/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h
--- ROUTE.orig/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h	2003-12-20 17:43:09.000000000 +0100
+++ ROUTE/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,22 +0,0 @@
-/* Header file for iptables ip6t_ROUTE target
- *
- * (C) 2003 by Cédric 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 IP6T_ROUTE_IFNAMSIZ 16
-
-struct ip6t_route_target_info {
-	char      oif[IP6T_ROUTE_IFNAMSIZ];     /* Output Interface Name */
-	char      iif[IP6T_ROUTE_IFNAMSIZ];     /* Input Interface Name  */
-	u_int32_t gw[4];                        /* IPv6 address of gateway */
-	u_int8_t  flags;
-};
-
-/* Values for "flags" field */
-#define IP6T_ROUTE_CONTINUE        0x01
-
-#endif /*_IP6T_ROUTE_H_target*/
diff -Nru ROUTE.orig/linux/net/ipv4/netfilter/Config.in.ladd ROUTE/linux/net/ipv4/netfilter/Config.in.ladd
--- ROUTE.orig/linux/net/ipv4/netfilter/Config.in.ladd	2003-12-18 19:47:54.000000000 +0100
+++ ROUTE/linux/net/ipv4/netfilter/Config.in.ladd	1970-01-01 01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-    dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
-    dep_tristate '    ROUTE target support' CONFIG_IP_NF_TARGET_ROUTE $CONFIG_IP_NF_MANGLE
- 
\ Pas de fin de ligne à la fin du fichier.
diff -Nru ROUTE.orig/linux/net/ipv4/netfilter/ipt_ROUTE.c ROUTE/linux/net/ipv4/netfilter/ipt_ROUTE.c
--- ROUTE.orig/linux/net/ipv4/netfilter/ipt_ROUTE.c	2003-12-18 19:47:54.000000000 +0100
+++ ROUTE/linux/net/ipv4/netfilter/ipt_ROUTE.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,369 +0,0 @@
-/*
- * 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.8 2003/07/25
- *
- * 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 preferred, 
- *      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 using the standard routing table. */
-	if ((err = ip_route_output_key(&rt, &key))) {
-		if (net_ratelimit()) 
-			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) {
-		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.
-	 */
-	if (net_ratelimit()) 
-		DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n", 
-		       NIPQUAD(route_info->gw), ifindex, 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) 
-{
-	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 */
-		if (net_ratelimit()) 
-			DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif);
-		return NF_DROP;
-	}
-
-	/* Trying the standard way of routing packets */
-	switch (route(skb, ifindex, route_info)) {
-	case 1:
-		dev_put(dev_out);
-		if (route_info->flags & IPT_ROUTE_CONTINUE)
-			return IPT_CONTINUE;
-
-		ip_direct_send(skb);
-		return NF_STOLEN;
-
-	case 0:
-		/* Failed to send to oif. Trying the hard way */
-		if (route_info->flags & IPT_ROUTE_CONTINUE)
-			return NF_DROP;
-
-		if (net_ratelimit()) 
-			DEBUGP("ipt_ROUTE: forcing the use of %i\n",
-			       ifindex);
-
-		/* 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)) {
-			if (net_ratelimit()) 
-				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;
-		
-	default:
-		/* Unexpected error */
-		dev_put(dev_out);
-		return NF_DROP;
-	}
-}
-
-
-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 */
-		if (net_ratelimit()) 
-			DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->oif);
-		return NF_DROP;
-	}
-
-	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;
-
-	if (route_info->flags & IPT_ROUTE_CONTINUE)
-		return IPT_CONTINUE;
-
-	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.
-	 */
-	if (!(route_info->flags & IPT_ROUTE_CONTINUE)) {
-		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);
-
-	if (net_ratelimit()) 
-		DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
-
-	return IPT_CONTINUE;
-}
-
-
-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");
diff -Nru ROUTE.orig/linux/net/ipv4/netfilter/Kconfig.ladd ROUTE/linux/net/ipv4/netfilter/Kconfig.ladd
--- ROUTE.orig/linux/net/ipv4/netfilter/Kconfig.ladd	2003-12-21 21:09:27.000000000 +0100
+++ ROUTE/linux/net/ipv4/netfilter/Kconfig.ladd	1970-01-01 01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-config IP_NF_TARGET_ROUTE
-	tristate  'ROUTE target support'
-	depends on IP_NF_MANGLE
diff -Nru ROUTE.orig/linux/net/ipv4/netfilter/Makefile.ladd ROUTE/linux/net/ipv4/netfilter/Makefile.ladd
--- ROUTE.orig/linux/net/ipv4/netfilter/Makefile.ladd	2003-12-18 19:47:54.000000000 +0100
+++ ROUTE/linux/net/ipv4/netfilter/Makefile.ladd	1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
-obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o
diff -Nru ROUTE.orig/linux/net/ipv6/netfilter/Config.in.ladd ROUTE/linux/net/ipv6/netfilter/Config.in.ladd
--- ROUTE.orig/linux/net/ipv6/netfilter/Config.in.ladd	2003-12-20 17:43:09.000000000 +0100
+++ ROUTE/linux/net/ipv6/netfilter/Config.in.ladd	1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-    dep_tristate '    MARK target support' CONFIG_IP6_NF_TARGET_MARK $CONFIG_IP6_NF_MANGLE
-    dep_mbool '    ROUTE target support' CONFIG_IP6_NF_TARGET_ROUTE $CONFIG_IP6_NF_MANGLE
\ Pas de fin de ligne à la fin du fichier.
diff -Nru ROUTE.orig/linux/net/ipv6/netfilter/ip6t_ROUTE.c ROUTE/linux/net/ipv6/netfilter/ip6t_ROUTE.c
--- ROUTE.orig/linux/net/ipv6/netfilter/ip6t_ROUTE.c	2003-12-20 17:43:09.000000000 +0100
+++ ROUTE/linux/net/ipv6/netfilter/ip6t_ROUTE.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,289 +0,0 @@
-/*
- * This implements the ROUTE v6 target, which enables you to setup unusual
- * routes not supported by the standard kernel routing table.
- *
- * Copyright (C) 2003 Cedric de Launois <delaunois@info.ucl.ac.be>
- *
- * v 1.0 2003/08/05
- *
- * This software is distributed under GNU GPL v2, 1991
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/ipv6.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv6/ip6t_ROUTE.h>
-#include <linux/netdevice.h>
-#include <net/ipv6.h>
-#include <net/ndisc.h>
-#include <net/ip6_route.h>
-#include <linux/icmpv6.h>
-
-#if 1
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-#define NIP6(addr) \
-	ntohs((addr).s6_addr16[0]), \
-	ntohs((addr).s6_addr16[1]), \
-	ntohs((addr).s6_addr16[2]), \
-	ntohs((addr).s6_addr16[3]), \
-	ntohs((addr).s6_addr16[4]), \
-	ntohs((addr).s6_addr16[5]), \
-	ntohs((addr).s6_addr16[6]), \
-	ntohs((addr).s6_addr16[7])
-
-/* Route the packet according to the routing keys specified in
- * route_info. Keys are :
- *  - ifindex : 
- *      0 if no oif preferred, 
- *      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 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 
-route6(struct sk_buff *skb,
-       unsigned int ifindex,
-       const struct ip6t_route_target_info *route_info)
-{
-	struct rt6_info *rt = NULL;
-	struct ipv6hdr *ipv6h = skb->nh.ipv6h;
-	struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
-
-	DEBUGP("ip6t_ROUTE: called with: ");
-	DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
-	DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
-	DEBUGP("OUT=%s\n", route_info->oif);
-	
-	if (ipv6_addr_any(gw))
-		rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
-	else
-		rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
-
-	if (!rt)
-		goto no_route;
-
-	DEBUGP("ip6t_ROUTE: routing gives: ");
-	DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
-	DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
-	DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
-
-	if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
-		goto wrong_route;
-	
-	if (!rt->rt6i_nexthop) {
-		DEBUGP("ip6t_ROUTE: discovering neighbour\n");
-		rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
-	}
-
-	/* Drop old route. */
-	dst_release(skb->dst);
-	skb->dst = &rt->u.dst;
-	skb->dev = rt->rt6i_dev;
-	return 1;
-
- wrong_route:
-	dst_release(&rt->u.dst);
- no_route:
-	if (!net_ratelimit())
-		return 0;
-
-	printk("ip6t_ROUTE: no explicit route found ");
-	if (ifindex)
-		printk("via interface %s ", route_info->oif);
-	if (!ipv6_addr_any(gw))
-		printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
-	printk("\n");
-	return 0;
-}
-
-
-/* Stolen from ip6_output_finish
- * 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 "ip6t_ROUTE: no hdr & no neighbour cache!\n");
-		kfree_skb(skb);
-	}
-}
-
-
-static unsigned int 
-route6_oif(const struct ip6t_route_target_info *route_info,
-	   struct sk_buff *skb) 
-{
-	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 */
-		if (net_ratelimit()) 
-			DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
-
-		if (route_info->flags & IP6T_ROUTE_CONTINUE)
-			return IP6T_CONTINUE;
-		else
-			return NF_DROP;
-	}
-
-	/* Trying the standard way of routing packets */
-	if (route6(skb, ifindex, route_info)) {
-		dev_put(dev_out);
-		if (route_info->flags & IP6T_ROUTE_CONTINUE)
-			return IP6T_CONTINUE;
-		
-		ip_direct_send(skb);
-		return NF_STOLEN;
-	} else 
-		return NF_DROP;
-}
-
-
-static unsigned int 
-route6_gw(const struct ip6t_route_target_info *route_info,
-	  struct sk_buff *skb) 
-{
-	if (route6(skb, 0, route_info)) {
-		if (route_info->flags & IP6T_ROUTE_CONTINUE)
-			return IP6T_CONTINUE;
-
-		ip_direct_send(skb);
-		return NF_STOLEN;
-	} else
-		return NF_DROP;
-}
-
-
-static unsigned int 
-ip6t_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 ip6t_route_target_info *route_info = targinfo;
-	struct sk_buff *skb = *pskb;
-	struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
-
-	if (route_info->flags & IP6T_ROUTE_CONTINUE)
-		goto do_it;
-
-	/* If we are at PREROUTING or INPUT hook
-	 * the TTL isn't decreased by the IP stack
-	 */
-	if (hooknum == NF_IP6_PRE_ROUTING ||
-	    hooknum == NF_IP6_LOCAL_IN) {
-
-		struct ipv6hdr *ipv6h = skb->nh.ipv6h;
-
-		if (ipv6h->hop_limit <= 1) {
-			/* Force OUTPUT device used as source address */
-			skb->dev = skb->dst->dev;
-
-			icmpv6_send(skb, ICMPV6_TIME_EXCEED, 
-				    ICMPV6_EXC_HOPLIMIT, 0, skb->dev);
-
-			return NF_DROP;
-		}
-
-		ipv6h->hop_limit--;
-	}
-
-
- do_it:
-	if (route_info->oif[0]) 
-		return route6_oif(route_info, *pskb);
-	
-	if (!ipv6_addr_any(gw))
-		return route6_gw(route_info, *pskb);
-
-	if (net_ratelimit()) 
-		DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
-
-	return IP6T_CONTINUE;
-}
-
-
-static int 
-ip6t_route_checkentry(const char *tablename,
-		      const struct ip6t_entry *e,
-		      void *targinfo,
-		      unsigned int targinfosize,
-		      unsigned int hook_mask)
-{
-	if (strcmp(tablename, "mangle") != 0) {
-		printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
-		return 0;
-	}
-
-	if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) {
-		printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       IP6T_ALIGN(sizeof(struct ip6t_route_target_info)));
-		return 0;
-	}
-
-	return 1;
-}
-
-
-static struct ip6t_target ip6t_route_reg = {
-	.name       = "ROUTE",
-	.target     = ip6t_route_target,
-	.checkentry = ip6t_route_checkentry,
-	.me         = THIS_MODULE
-};
-
-
-static int __init init(void)
-{
-	printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
-	if (ip6t_register_target(&ip6t_route_reg))
-		return -EINVAL;
-
-	return 0;
-}
-
-
-static void __exit fini(void)
-{
-	ip6t_unregister_target(&ip6t_route_reg);
-}
-
-module_init(init);
-module_exit(fini);
-MODULE_LICENSE("GPL");
diff -Nru ROUTE.orig/linux/net/ipv6/netfilter/Kconfig.ladd ROUTE/linux/net/ipv6/netfilter/Kconfig.ladd
--- ROUTE.orig/linux/net/ipv6/netfilter/Kconfig.ladd	2003-12-23 12:41:11.000000000 +0100
+++ ROUTE/linux/net/ipv6/netfilter/Kconfig.ladd	1970-01-01 01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-config IP6_NF_TARGET_ROUTE
-	tristate '    ROUTE target support'
-	depends on IP6_NF_MANGLE
diff -Nru ROUTE.orig/linux/net/ipv6/netfilter/Makefile.ladd ROUTE/linux/net/ipv6/netfilter/Makefile.ladd
--- ROUTE.orig/linux/net/ipv6/netfilter/Makefile.ladd	2003-12-20 17:43:09.000000000 +0100
+++ ROUTE/linux/net/ipv6/netfilter/Makefile.ladd	1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
-obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o
diff -Nru ROUTE.orig/linux-2.4/Documentation/Configure.help.ladd ROUTE/linux-2.4/Documentation/Configure.help.ladd
--- ROUTE.orig/linux-2.4/Documentation/Configure.help.ladd	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/Documentation/Configure.help.ladd	2004-02-19 12:30:08.000000000 +0100
@@ -0,0 +1,16 @@
+CONFIG_IP_NF_TARGET_MARK
+ROUTE target support
+CONFIG_IP_NF_TARGET_ROUTE
+  This option adds a `ROUTE' target, which enables you to setup unusual
+  routes. For example, the ROUTE lets you 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.
+
+  The target can be or not 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'.
+
diff -Nru ROUTE.orig/linux-2.4/Documentation/Configure.help.ladd_2 ROUTE/linux-2.4/Documentation/Configure.help.ladd_2
--- ROUTE.orig/linux-2.4/Documentation/Configure.help.ladd_2	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/Documentation/Configure.help.ladd_2	2004-03-05 10:30:26.000000000 +0100
@@ -0,0 +1,12 @@
+CONFIG_IP6_NF_TARGET_MARK
+ROUTE target support
+CONFIG_IP6_NF_TARGET_ROUTE
+  This option adds a `ROUTE' target, which enables you to setup unusual
+  routes. The ROUTE target is also able to change the incoming interface
+  of a packet.
+
+  The target can be or not a final target. It has to be used inside the 
+  mangle table.
+  
+  Not working as a module.
+
diff -Nru ROUTE.orig/linux-2.4/include/linux/netfilter_ipv4/ipt_ROUTE.h ROUTE/linux-2.4/include/linux/netfilter_ipv4/ipt_ROUTE.h
--- ROUTE.orig/linux-2.4/include/linux/netfilter_ipv4/ipt_ROUTE.h	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/include/linux/netfilter_ipv4/ipt_ROUTE.h	2003-12-18 19:47:54.000000000 +0100
@@ -0,0 +1,22 @@
+/* Header file for iptables ipt_ROUTE target
+ *
+ * (C) 2002 by Cédric 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];      /* Output Interface Name */
+	char      iif[IPT_ROUTE_IFNAMSIZ];      /* Input Interface Name  */
+	u_int32_t gw;                           /* IP address of gateway */
+	u_int8_t  flags;
+};
+
+/* Values for "flags" field */
+#define IPT_ROUTE_CONTINUE        0x01
+
+#endif /*_IPT_ROUTE_H_target*/
diff -Nru ROUTE.orig/linux-2.4/include/linux/netfilter_ipv6/ip6t_ROUTE.h ROUTE/linux-2.4/include/linux/netfilter_ipv6/ip6t_ROUTE.h
--- ROUTE.orig/linux-2.4/include/linux/netfilter_ipv6/ip6t_ROUTE.h	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/include/linux/netfilter_ipv6/ip6t_ROUTE.h	2003-12-20 17:43:09.000000000 +0100
@@ -0,0 +1,22 @@
+/* Header file for iptables ip6t_ROUTE target
+ *
+ * (C) 2003 by Cédric 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 IP6T_ROUTE_IFNAMSIZ 16
+
+struct ip6t_route_target_info {
+	char      oif[IP6T_ROUTE_IFNAMSIZ];     /* Output Interface Name */
+	char      iif[IP6T_ROUTE_IFNAMSIZ];     /* Input Interface Name  */
+	u_int32_t gw[4];                        /* IPv6 address of gateway */
+	u_int8_t  flags;
+};
+
+/* Values for "flags" field */
+#define IP6T_ROUTE_CONTINUE        0x01
+
+#endif /*_IP6T_ROUTE_H_target*/
diff -Nru ROUTE.orig/linux-2.4/net/ipv4/netfilter/Config.in.ladd ROUTE/linux-2.4/net/ipv4/netfilter/Config.in.ladd
--- ROUTE.orig/linux-2.4/net/ipv4/netfilter/Config.in.ladd	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/net/ipv4/netfilter/Config.in.ladd	2003-12-18 19:47:54.000000000 +0100
@@ -0,0 +1,3 @@
+    dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
+    dep_tristate '    ROUTE target support' CONFIG_IP_NF_TARGET_ROUTE $CONFIG_IP_NF_MANGLE
+ 
\ Pas de fin de ligne à la fin du fichier.
diff -Nru ROUTE.orig/linux-2.4/net/ipv4/netfilter/ipt_ROUTE.c ROUTE/linux-2.4/net/ipv4/netfilter/ipt_ROUTE.c
--- ROUTE.orig/linux-2.4/net/ipv4/netfilter/ipt_ROUTE.c	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/net/ipv4/netfilter/ipt_ROUTE.c	2003-12-18 19:47:54.000000000 +0100
@@ -0,0 +1,369 @@
+/*
+ * 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.8 2003/07/25
+ *
+ * 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 preferred, 
+ *      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 using the standard routing table. */
+	if ((err = ip_route_output_key(&rt, &key))) {
+		if (net_ratelimit()) 
+			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) {
+		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.
+	 */
+	if (net_ratelimit()) 
+		DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n", 
+		       NIPQUAD(route_info->gw), ifindex, 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) 
+{
+	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 */
+		if (net_ratelimit()) 
+			DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif);
+		return NF_DROP;
+	}
+
+	/* Trying the standard way of routing packets */
+	switch (route(skb, ifindex, route_info)) {
+	case 1:
+		dev_put(dev_out);
+		if (route_info->flags & IPT_ROUTE_CONTINUE)
+			return IPT_CONTINUE;
+
+		ip_direct_send(skb);
+		return NF_STOLEN;
+
+	case 0:
+		/* Failed to send to oif. Trying the hard way */
+		if (route_info->flags & IPT_ROUTE_CONTINUE)
+			return NF_DROP;
+
+		if (net_ratelimit()) 
+			DEBUGP("ipt_ROUTE: forcing the use of %i\n",
+			       ifindex);
+
+		/* 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)) {
+			if (net_ratelimit()) 
+				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;
+		
+	default:
+		/* Unexpected error */
+		dev_put(dev_out);
+		return NF_DROP;
+	}
+}
+
+
+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 */
+		if (net_ratelimit()) 
+			DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->oif);
+		return NF_DROP;
+	}
+
+	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;
+
+	if (route_info->flags & IPT_ROUTE_CONTINUE)
+		return IPT_CONTINUE;
+
+	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.
+	 */
+	if (!(route_info->flags & IPT_ROUTE_CONTINUE)) {
+		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);
+
+	if (net_ratelimit()) 
+		DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
+
+	return IPT_CONTINUE;
+}
+
+
+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");
diff -Nru ROUTE.orig/linux-2.4/net/ipv4/netfilter/Makefile.ladd ROUTE/linux-2.4/net/ipv4/netfilter/Makefile.ladd
--- ROUTE.orig/linux-2.4/net/ipv4/netfilter/Makefile.ladd	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/net/ipv4/netfilter/Makefile.ladd	2003-12-18 19:47:54.000000000 +0100
@@ -0,0 +1,2 @@
+obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o
diff -Nru ROUTE.orig/linux-2.4/net/ipv6/netfilter/Config.in.ladd ROUTE/linux-2.4/net/ipv6/netfilter/Config.in.ladd
--- ROUTE.orig/linux-2.4/net/ipv6/netfilter/Config.in.ladd	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/net/ipv6/netfilter/Config.in.ladd	2003-12-20 17:43:09.000000000 +0100
@@ -0,0 +1,2 @@
+    dep_tristate '    MARK target support' CONFIG_IP6_NF_TARGET_MARK $CONFIG_IP6_NF_MANGLE
+    dep_mbool '    ROUTE target support' CONFIG_IP6_NF_TARGET_ROUTE $CONFIG_IP6_NF_MANGLE
\ Pas de fin de ligne à la fin du fichier.
diff -Nru ROUTE.orig/linux-2.4/net/ipv6/netfilter/CVS/Entries ROUTE/linux-2.4/net/ipv6/netfilter/CVS/Entries
--- ROUTE.orig/linux-2.4/net/ipv6/netfilter/CVS/Entries	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/net/ipv6/netfilter/CVS/Entries	2004-03-08 10:06:41.000000000 +0100
@@ -0,0 +1,5 @@
+/Config.in.ladd/1.1/Sat Dec 20 16:43:09 2003//
+/Kconfig.ladd/1.1/Tue Dec 23 11:41:11 2003//
+/Makefile.ladd/1.1/Sat Dec 20 16:43:09 2003//
+/ip6t_ROUTE.c/1.1/Sat Dec 20 16:43:09 2003//
+D
diff -Nru ROUTE.orig/linux-2.4/net/ipv6/netfilter/CVS/Repository ROUTE/linux-2.4/net/ipv6/netfilter/CVS/Repository
--- ROUTE.orig/linux-2.4/net/ipv6/netfilter/CVS/Repository	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/net/ipv6/netfilter/CVS/Repository	2004-03-08 10:06:41.000000000 +0100
@@ -0,0 +1 @@
+patch-o-matic-ng/ROUTE/linux/net/ipv6/netfilter
diff -Nru ROUTE.orig/linux-2.4/net/ipv6/netfilter/CVS/Root ROUTE/linux-2.4/net/ipv6/netfilter/CVS/Root
--- ROUTE.orig/linux-2.4/net/ipv6/netfilter/CVS/Root	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/net/ipv6/netfilter/CVS/Root	2004-03-08 10:06:41.000000000 +0100
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ROUTE.orig/linux-2.4/net/ipv6/netfilter/ip6t_ROUTE.c ROUTE/linux-2.4/net/ipv6/netfilter/ip6t_ROUTE.c
--- ROUTE.orig/linux-2.4/net/ipv6/netfilter/ip6t_ROUTE.c	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/net/ipv6/netfilter/ip6t_ROUTE.c	2003-12-20 17:43:09.000000000 +0100
@@ -0,0 +1,289 @@
+/*
+ * This implements the ROUTE v6 target, which enables you to setup unusual
+ * routes not supported by the standard kernel routing table.
+ *
+ * Copyright (C) 2003 Cedric de Launois <delaunois@info.ucl.ac.be>
+ *
+ * v 1.0 2003/08/05
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_ROUTE.h>
+#include <linux/netdevice.h>
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/ip6_route.h>
+#include <linux/icmpv6.h>
+
+#if 1
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define NIP6(addr) \
+	ntohs((addr).s6_addr16[0]), \
+	ntohs((addr).s6_addr16[1]), \
+	ntohs((addr).s6_addr16[2]), \
+	ntohs((addr).s6_addr16[3]), \
+	ntohs((addr).s6_addr16[4]), \
+	ntohs((addr).s6_addr16[5]), \
+	ntohs((addr).s6_addr16[6]), \
+	ntohs((addr).s6_addr16[7])
+
+/* Route the packet according to the routing keys specified in
+ * route_info. Keys are :
+ *  - ifindex : 
+ *      0 if no oif preferred, 
+ *      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 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 
+route6(struct sk_buff *skb,
+       unsigned int ifindex,
+       const struct ip6t_route_target_info *route_info)
+{
+	struct rt6_info *rt = NULL;
+	struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+	struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
+
+	DEBUGP("ip6t_ROUTE: called with: ");
+	DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
+	DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
+	DEBUGP("OUT=%s\n", route_info->oif);
+	
+	if (ipv6_addr_any(gw))
+		rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
+	else
+		rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
+
+	if (!rt)
+		goto no_route;
+
+	DEBUGP("ip6t_ROUTE: routing gives: ");
+	DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
+	DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
+	DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
+
+	if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
+		goto wrong_route;
+	
+	if (!rt->rt6i_nexthop) {
+		DEBUGP("ip6t_ROUTE: discovering neighbour\n");
+		rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
+	}
+
+	/* Drop old route. */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+	skb->dev = rt->rt6i_dev;
+	return 1;
+
+ wrong_route:
+	dst_release(&rt->u.dst);
+ no_route:
+	if (!net_ratelimit())
+		return 0;
+
+	printk("ip6t_ROUTE: no explicit route found ");
+	if (ifindex)
+		printk("via interface %s ", route_info->oif);
+	if (!ipv6_addr_any(gw))
+		printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
+	printk("\n");
+	return 0;
+}
+
+
+/* Stolen from ip6_output_finish
+ * 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 "ip6t_ROUTE: no hdr & no neighbour cache!\n");
+		kfree_skb(skb);
+	}
+}
+
+
+static unsigned int 
+route6_oif(const struct ip6t_route_target_info *route_info,
+	   struct sk_buff *skb) 
+{
+	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 */
+		if (net_ratelimit()) 
+			DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
+
+		if (route_info->flags & IP6T_ROUTE_CONTINUE)
+			return IP6T_CONTINUE;
+		else
+			return NF_DROP;
+	}
+
+	/* Trying the standard way of routing packets */
+	if (route6(skb, ifindex, route_info)) {
+		dev_put(dev_out);
+		if (route_info->flags & IP6T_ROUTE_CONTINUE)
+			return IP6T_CONTINUE;
+		
+		ip_direct_send(skb);
+		return NF_STOLEN;
+	} else 
+		return NF_DROP;
+}
+
+
+static unsigned int 
+route6_gw(const struct ip6t_route_target_info *route_info,
+	  struct sk_buff *skb) 
+{
+	if (route6(skb, 0, route_info)) {
+		if (route_info->flags & IP6T_ROUTE_CONTINUE)
+			return IP6T_CONTINUE;
+
+		ip_direct_send(skb);
+		return NF_STOLEN;
+	} else
+		return NF_DROP;
+}
+
+
+static unsigned int 
+ip6t_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 ip6t_route_target_info *route_info = targinfo;
+	struct sk_buff *skb = *pskb;
+	struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
+
+	if (route_info->flags & IP6T_ROUTE_CONTINUE)
+		goto do_it;
+
+	/* If we are at PREROUTING or INPUT hook
+	 * the TTL isn't decreased by the IP stack
+	 */
+	if (hooknum == NF_IP6_PRE_ROUTING ||
+	    hooknum == NF_IP6_LOCAL_IN) {
+
+		struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+
+		if (ipv6h->hop_limit <= 1) {
+			/* Force OUTPUT device used as source address */
+			skb->dev = skb->dst->dev;
+
+			icmpv6_send(skb, ICMPV6_TIME_EXCEED, 
+				    ICMPV6_EXC_HOPLIMIT, 0, skb->dev);
+
+			return NF_DROP;
+		}
+
+		ipv6h->hop_limit--;
+	}
+
+
+ do_it:
+	if (route_info->oif[0]) 
+		return route6_oif(route_info, *pskb);
+	
+	if (!ipv6_addr_any(gw))
+		return route6_gw(route_info, *pskb);
+
+	if (net_ratelimit()) 
+		DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
+
+	return IP6T_CONTINUE;
+}
+
+
+static int 
+ip6t_route_checkentry(const char *tablename,
+		      const struct ip6t_entry *e,
+		      void *targinfo,
+		      unsigned int targinfosize,
+		      unsigned int hook_mask)
+{
+	if (strcmp(tablename, "mangle") != 0) {
+		printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
+		return 0;
+	}
+
+	if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) {
+		printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       IP6T_ALIGN(sizeof(struct ip6t_route_target_info)));
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static struct ip6t_target ip6t_route_reg = {
+	.name       = "ROUTE",
+	.target     = ip6t_route_target,
+	.checkentry = ip6t_route_checkentry,
+	.me         = THIS_MODULE
+};
+
+
+static int __init init(void)
+{
+	printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
+	if (ip6t_register_target(&ip6t_route_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+
+static void __exit fini(void)
+{
+	ip6t_unregister_target(&ip6t_route_reg);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru ROUTE.orig/linux-2.4/net/ipv6/netfilter/Makefile.ladd ROUTE/linux-2.4/net/ipv6/netfilter/Makefile.ladd
--- ROUTE.orig/linux-2.4/net/ipv6/netfilter/Makefile.ladd	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.4/net/ipv6/netfilter/Makefile.ladd	2003-12-20 17:43:09.000000000 +0100
@@ -0,0 +1,2 @@
+obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o
diff -Nru ROUTE.orig/linux-2.6/include/linux/netfilter_ipv4/ipt_ROUTE.h ROUTE/linux-2.6/include/linux/netfilter_ipv4/ipt_ROUTE.h
--- ROUTE.orig/linux-2.6/include/linux/netfilter_ipv4/ipt_ROUTE.h	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.6/include/linux/netfilter_ipv4/ipt_ROUTE.h	2003-12-18 19:47:54.000000000 +0100
@@ -0,0 +1,22 @@
+/* Header file for iptables ipt_ROUTE target
+ *
+ * (C) 2002 by Cédric 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];      /* Output Interface Name */
+	char      iif[IPT_ROUTE_IFNAMSIZ];      /* Input Interface Name  */
+	u_int32_t gw;                           /* IP address of gateway */
+	u_int8_t  flags;
+};
+
+/* Values for "flags" field */
+#define IPT_ROUTE_CONTINUE        0x01
+
+#endif /*_IPT_ROUTE_H_target*/
diff -Nru ROUTE.orig/linux-2.6/include/linux/netfilter_ipv6/ip6t_ROUTE.h ROUTE/linux-2.6/include/linux/netfilter_ipv6/ip6t_ROUTE.h
--- ROUTE.orig/linux-2.6/include/linux/netfilter_ipv6/ip6t_ROUTE.h	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.6/include/linux/netfilter_ipv6/ip6t_ROUTE.h	2003-12-20 17:43:09.000000000 +0100
@@ -0,0 +1,22 @@
+/* Header file for iptables ip6t_ROUTE target
+ *
+ * (C) 2003 by Cédric 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 IP6T_ROUTE_IFNAMSIZ 16
+
+struct ip6t_route_target_info {
+	char      oif[IP6T_ROUTE_IFNAMSIZ];     /* Output Interface Name */
+	char      iif[IP6T_ROUTE_IFNAMSIZ];     /* Input Interface Name  */
+	u_int32_t gw[4];                        /* IPv6 address of gateway */
+	u_int8_t  flags;
+};
+
+/* Values for "flags" field */
+#define IP6T_ROUTE_CONTINUE        0x01
+
+#endif /*_IP6T_ROUTE_H_target*/
diff -Nru ROUTE.orig/linux-2.6/net/ipv4/netfilter/ipt_ROUTE.c ROUTE/linux-2.6/net/ipv4/netfilter/ipt_ROUTE.c
--- ROUTE.orig/linux-2.6/net/ipv4/netfilter/ipt_ROUTE.c	2004-02-22 18:29:10.000000000 +0100
+++ ROUTE/linux-2.6/net/ipv4/netfilter/ipt_ROUTE.c	2004-03-08 15:19:07.000000000 +0100
@@ -19,6 +19,7 @@
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/icmp.h>
+#include <net/checksum.h>
 
 #if 0
 #define DEBUGP printk
@@ -28,6 +29,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Cedric de Launois <delaunois@info.ucl.ac.be>");
+MODULE_DESCRIPTION("iptables ROUTE target module");
 
 /* Try to route the packet according to the routing keys specified in
  * route_info. Keys are :
@@ -53,19 +55,24 @@
 	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) 
+	struct flowi fl = {
+		.oif = ifindex,
+		.nl_u = {
+			.ip4_u = {
+				.daddr = iph->daddr,
+				.saddr = 0,
+				.tos = RT_TOS(iph->tos),
+				.scope = RT_SCOPE_UNIVERSE,
+			}
+		} 
 	};
 	
 	/* The destination address may be overloaded by the target */
 	if (route_info->gw)
-		key.dst = route_info->gw;
+		fl.fld_dst = route_info->gw;
 	
 	/* Trying to route the packet using the standard routing table. */
-	if ((err = ip_route_output_key(&rt, &key))) {
+	if ((err = ip_route_output_key(&rt, &fl))) {
 		if (net_ratelimit()) 
 			DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err);
 		return -1;
@@ -262,10 +269,21 @@
 
 		if (iph->ttl <= 1) {
 			struct rtable *rt;
+			struct flowi fl = {
+				.oif = 0,
+				.nl_u = {
+					.ip4_u = {
+						.daddr = iph->daddr,
+						.saddr = iph->saddr,
+						.tos = RT_TOS(iph->tos),
+						.scope = ((iph->tos & RTO_ONLINK) ?
+							  RT_SCOPE_LINK :
+							  RT_SCOPE_UNIVERSE)
+					}
+				} 
+			};
 
-			if (ip_route_output(&rt, iph->saddr, iph->daddr,
-					    RT_TOS(iph->tos) | RTO_CONN,
-					    0)) {
+			if (ip_route_output_key(&rt, &fl)) {
 				return NF_DROP;
 			}
 
@@ -284,6 +302,7 @@
 		}
 
 		ip_decrease_ttl(iph);
+		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 	}
 
 	/* Tell conntrack to forget this packet since it may get confused 
diff -Nru ROUTE.orig/linux-2.6/net/ipv4/netfilter/Kconfig.ladd ROUTE/linux-2.6/net/ipv4/netfilter/Kconfig.ladd
--- ROUTE.orig/linux-2.6/net/ipv4/netfilter/Kconfig.ladd	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.6/net/ipv4/netfilter/Kconfig.ladd	2004-03-08 14:02:45.000000000 +0100
@@ -0,0 +1,16 @@
+config IP_NF_TARGET_ROUTE
+	tristate  'ROUTE target support'
+	depends on IP_NF_MANGLE
+	help
+	  This option adds a `ROUTE' target, which enables you to setup unusual
+	  routes. For example, the ROUTE lets you 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.
+	
+	  The target can be or not 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'.
diff -Nru ROUTE.orig/linux-2.6/net/ipv4/netfilter/Makefile.ladd ROUTE/linux-2.6/net/ipv4/netfilter/Makefile.ladd
--- ROUTE.orig/linux-2.6/net/ipv4/netfilter/Makefile.ladd	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.6/net/ipv4/netfilter/Makefile.ladd	2003-12-18 19:47:54.000000000 +0100
@@ -0,0 +1,2 @@
+obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o
diff -Nru ROUTE.orig/linux-2.6/net/ipv6/netfilter/ip6t_ROUTE.c ROUTE/linux-2.6/net/ipv6/netfilter/ip6t_ROUTE.c
--- ROUTE.orig/linux-2.6/net/ipv6/netfilter/ip6t_ROUTE.c	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.6/net/ipv6/netfilter/ip6t_ROUTE.c	2003-12-20 17:43:09.000000000 +0100
@@ -0,0 +1,289 @@
+/*
+ * This implements the ROUTE v6 target, which enables you to setup unusual
+ * routes not supported by the standard kernel routing table.
+ *
+ * Copyright (C) 2003 Cedric de Launois <delaunois@info.ucl.ac.be>
+ *
+ * v 1.0 2003/08/05
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_ROUTE.h>
+#include <linux/netdevice.h>
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/ip6_route.h>
+#include <linux/icmpv6.h>
+
+#if 1
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define NIP6(addr) \
+	ntohs((addr).s6_addr16[0]), \
+	ntohs((addr).s6_addr16[1]), \
+	ntohs((addr).s6_addr16[2]), \
+	ntohs((addr).s6_addr16[3]), \
+	ntohs((addr).s6_addr16[4]), \
+	ntohs((addr).s6_addr16[5]), \
+	ntohs((addr).s6_addr16[6]), \
+	ntohs((addr).s6_addr16[7])
+
+/* Route the packet according to the routing keys specified in
+ * route_info. Keys are :
+ *  - ifindex : 
+ *      0 if no oif preferred, 
+ *      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 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 
+route6(struct sk_buff *skb,
+       unsigned int ifindex,
+       const struct ip6t_route_target_info *route_info)
+{
+	struct rt6_info *rt = NULL;
+	struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+	struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
+
+	DEBUGP("ip6t_ROUTE: called with: ");
+	DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
+	DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
+	DEBUGP("OUT=%s\n", route_info->oif);
+	
+	if (ipv6_addr_any(gw))
+		rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
+	else
+		rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
+
+	if (!rt)
+		goto no_route;
+
+	DEBUGP("ip6t_ROUTE: routing gives: ");
+	DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
+	DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
+	DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
+
+	if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
+		goto wrong_route;
+	
+	if (!rt->rt6i_nexthop) {
+		DEBUGP("ip6t_ROUTE: discovering neighbour\n");
+		rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
+	}
+
+	/* Drop old route. */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+	skb->dev = rt->rt6i_dev;
+	return 1;
+
+ wrong_route:
+	dst_release(&rt->u.dst);
+ no_route:
+	if (!net_ratelimit())
+		return 0;
+
+	printk("ip6t_ROUTE: no explicit route found ");
+	if (ifindex)
+		printk("via interface %s ", route_info->oif);
+	if (!ipv6_addr_any(gw))
+		printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
+	printk("\n");
+	return 0;
+}
+
+
+/* Stolen from ip6_output_finish
+ * 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 "ip6t_ROUTE: no hdr & no neighbour cache!\n");
+		kfree_skb(skb);
+	}
+}
+
+
+static unsigned int 
+route6_oif(const struct ip6t_route_target_info *route_info,
+	   struct sk_buff *skb) 
+{
+	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 */
+		if (net_ratelimit()) 
+			DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
+
+		if (route_info->flags & IP6T_ROUTE_CONTINUE)
+			return IP6T_CONTINUE;
+		else
+			return NF_DROP;
+	}
+
+	/* Trying the standard way of routing packets */
+	if (route6(skb, ifindex, route_info)) {
+		dev_put(dev_out);
+		if (route_info->flags & IP6T_ROUTE_CONTINUE)
+			return IP6T_CONTINUE;
+		
+		ip_direct_send(skb);
+		return NF_STOLEN;
+	} else 
+		return NF_DROP;
+}
+
+
+static unsigned int 
+route6_gw(const struct ip6t_route_target_info *route_info,
+	  struct sk_buff *skb) 
+{
+	if (route6(skb, 0, route_info)) {
+		if (route_info->flags & IP6T_ROUTE_CONTINUE)
+			return IP6T_CONTINUE;
+
+		ip_direct_send(skb);
+		return NF_STOLEN;
+	} else
+		return NF_DROP;
+}
+
+
+static unsigned int 
+ip6t_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 ip6t_route_target_info *route_info = targinfo;
+	struct sk_buff *skb = *pskb;
+	struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
+
+	if (route_info->flags & IP6T_ROUTE_CONTINUE)
+		goto do_it;
+
+	/* If we are at PREROUTING or INPUT hook
+	 * the TTL isn't decreased by the IP stack
+	 */
+	if (hooknum == NF_IP6_PRE_ROUTING ||
+	    hooknum == NF_IP6_LOCAL_IN) {
+
+		struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+
+		if (ipv6h->hop_limit <= 1) {
+			/* Force OUTPUT device used as source address */
+			skb->dev = skb->dst->dev;
+
+			icmpv6_send(skb, ICMPV6_TIME_EXCEED, 
+				    ICMPV6_EXC_HOPLIMIT, 0, skb->dev);
+
+			return NF_DROP;
+		}
+
+		ipv6h->hop_limit--;
+	}
+
+
+ do_it:
+	if (route_info->oif[0]) 
+		return route6_oif(route_info, *pskb);
+	
+	if (!ipv6_addr_any(gw))
+		return route6_gw(route_info, *pskb);
+
+	if (net_ratelimit()) 
+		DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
+
+	return IP6T_CONTINUE;
+}
+
+
+static int 
+ip6t_route_checkentry(const char *tablename,
+		      const struct ip6t_entry *e,
+		      void *targinfo,
+		      unsigned int targinfosize,
+		      unsigned int hook_mask)
+{
+	if (strcmp(tablename, "mangle") != 0) {
+		printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
+		return 0;
+	}
+
+	if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) {
+		printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       IP6T_ALIGN(sizeof(struct ip6t_route_target_info)));
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static struct ip6t_target ip6t_route_reg = {
+	.name       = "ROUTE",
+	.target     = ip6t_route_target,
+	.checkentry = ip6t_route_checkentry,
+	.me         = THIS_MODULE
+};
+
+
+static int __init init(void)
+{
+	printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
+	if (ip6t_register_target(&ip6t_route_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+
+static void __exit fini(void)
+{
+	ip6t_unregister_target(&ip6t_route_reg);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru ROUTE.orig/linux-2.6/net/ipv6/netfilter/Kconfig.ladd ROUTE/linux-2.6/net/ipv6/netfilter/Kconfig.ladd
--- ROUTE.orig/linux-2.6/net/ipv6/netfilter/Kconfig.ladd	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.6/net/ipv6/netfilter/Kconfig.ladd	2004-03-08 15:06:42.000000000 +0100
@@ -0,0 +1,11 @@
+config IP6_NF_TARGET_ROUTE
+	tristate '    ROUTE target support'
+	depends on IP6_NF_MANGLE
+	help
+	  This option adds a `ROUTE' target, which enables you to setup unusual
+	  routes. The ROUTE target is also able to change the incoming interface
+	  of a packet.
+	
+	  The target can be or not a final target. It has to be used inside the 
+	  mangle table.
+
diff -Nru ROUTE.orig/linux-2.6/net/ipv6/netfilter/Makefile.ladd ROUTE/linux-2.6/net/ipv6/netfilter/Makefile.ladd
--- ROUTE.orig/linux-2.6/net/ipv6/netfilter/Makefile.ladd	1970-01-01 01:00:00.000000000 +0100
+++ ROUTE/linux-2.6/net/ipv6/netfilter/Makefile.ladd	2003-12-20 17:43:09.000000000 +0100
@@ -0,0 +1,2 @@
+obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o

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

end of thread, other threads:[~2004-04-29 16:45 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-04-21  8:16 [PATCH] ROUTE target : update to pom-ng + new version for kernel 2.6.x Cedric de Launois
2004-04-24 23:03 ` Patrick McHardy
2004-04-25  0:01   ` Esteban Ribicic
2004-04-26  4:46     ` Henrik Nordstrom
2004-04-28 15:25   ` Cedric de Launois
2004-04-29 16:45     ` Patrick McHardy

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.