Add ROUTE target for netfilter, closes #595
authorFlorian Fainelli <florian@openwrt.org>
Tue, 22 Aug 2006 10:07:55 +0000 (10:07 +0000)
committerFlorian Fainelli <florian@openwrt.org>
Tue, 22 Aug 2006 10:07:55 +0000 (10:07 +0000)
SVN-Revision: 4620

openwrt/target/linux/au1000-2.6/config
openwrt/target/linux/brcm-2.6/config
openwrt/target/linux/brcm63xx-2.6/config
openwrt/target/linux/generic-2.6/patches/108-netfilter_route.patch [new file with mode: 0644]
openwrt/target/linux/rb532-2.6/config
openwrt/target/linux/sibyte-2.6/config
openwrt/target/linux/uml-2.6/config
openwrt/target/linux/x86-2.6/config
openwrt/target/linux/xscale-2.6/config

index b86c699a114758d5e13a3d9567d01fd6dc58e973..9c498efd102837d4fd60e4a3295e40e3fea3acee 100644 (file)
@@ -415,6 +415,7 @@ CONFIG_IP_NF_NAT=y
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
 # CONFIG_IP_NF_TARGET_NETMAP is not set
 # CONFIG_IP_NF_TARGET_SAME is not set
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
@@ -462,6 +463,7 @@ CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_IMQ=m
 # CONFIG_IP6_NF_TARGET_LOG is not set
 CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
 CONFIG_IP6_NF_MANGLE=m
 # CONFIG_IP6_NF_TARGET_HL is not set
 # CONFIG_IP6_NF_RAW is not set
index 180a45f58625196354b48260b2b10082ddf7ff31..75e9a1921f658edf22446cd5cbdd26d047ae42e4 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.17
-# Fri Jun 23 19:00:36 2006
+# Tue Aug 22 11:48:58 2006
 #
 CONFIG_MIPS=y
 
@@ -386,6 +386,7 @@ CONFIG_IP_NF_NAT=y
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
 # CONFIG_IP_NF_TARGET_NETMAP is not set
 # CONFIG_IP_NF_TARGET_SAME is not set
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
@@ -433,6 +434,7 @@ CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_IMQ=m
 # CONFIG_IP6_NF_TARGET_LOG is not set
 CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
 CONFIG_IP6_NF_MANGLE=m
 # CONFIG_IP6_NF_TARGET_HL is not set
 # CONFIG_IP6_NF_RAW is not set
index c5f8d58bf9d22ef39ee161de91bb55b8406d9a63..f7c7c0b0df7555ccff2d550e291bf077deb39852 100644 (file)
@@ -418,6 +418,7 @@ CONFIG_IP_NF_NAT=y
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
 # CONFIG_IP_NF_TARGET_NETMAP is not set
 # CONFIG_IP_NF_TARGET_SAME is not set
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
@@ -464,6 +465,7 @@ CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_IMQ=m
 # CONFIG_IP6_NF_TARGET_LOG is not set
 CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
 CONFIG_IP6_NF_MANGLE=m
 # CONFIG_IP6_NF_TARGET_HL is not set
 # CONFIG_IP6_NF_RAW is not set
diff --git a/openwrt/target/linux/generic-2.6/patches/108-netfilter_route.patch b/openwrt/target/linux/generic-2.6/patches/108-netfilter_route.patch
new file mode 100644 (file)
index 0000000..571d6a3
--- /dev/null
@@ -0,0 +1,914 @@
+diff -u'rNF^function' linux-2.6.16.7/include/linux/netfilter_ipv4/ipt_ROUTE.h linux-2.6.16.7-ROUTE/include/linux/netfilter_ipv4/ipt_ROUTE.h
+--- linux-2.6.16.7/include/linux/netfilter_ipv4/ipt_ROUTE.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7-ROUTE/include/linux/netfilter_ipv4/ipt_ROUTE.h       2006-06-14 16:40:49.000000000 +0200
+@@ -0,0 +1,23 @@
++/* 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
++#define IPT_ROUTE_TEE             0x02
++
++#endif /*_IPT_ROUTE_H_target*/
+diff -u'rNF^function' linux-2.6.16.7/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux-2.6.16.7-ROUTE/include/linux/netfilter_ipv6/ip6t_ROUTE.h
+--- linux-2.6.16.7/include/linux/netfilter_ipv6/ip6t_ROUTE.h    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7-ROUTE/include/linux/netfilter_ipv6/ip6t_ROUTE.h      2006-06-14 16:41:08.000000000 +0200
+@@ -0,0 +1,23 @@
++/* 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
++#define IP6T_ROUTE_TEE             0x02
++
++#endif /*_IP6T_ROUTE_H_target*/
+diff -u'rNF^function' linux-2.6.16.7/net/ipv4/netfilter/Kconfig linux-2.6.16.7-ROUTE/net/ipv4/netfilter/Kconfig
+--- linux-2.6.16.7/net/ipv4/netfilter/Kconfig   2006-06-14 16:05:44.000000000 +0200
++++ linux-2.6.16.7-ROUTE/net/ipv4/netfilter/Kconfig     2006-06-14 16:46:40.000000000 +0200
+@@ -491,6 +491,23 @@
+
+          To compile it as a module, choose M here.  If unsure, say N.
+
++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'.
++
+ config IP_NF_TARGET_NETMAP
+        tristate "NETMAP target support"
+        depends on IP_NF_NAT
+diff -u'rNF^function' linux-2.6.16.7/net/ipv4/netfilter/Makefile linux-2.6.16.7-ROUTE/net/ipv4/netfilter/Makefile
+--- linux-2.6.16.7/net/ipv4/netfilter/Makefile  2006-06-14 16:05:44.000000000 +0200
++++ linux-2.6.16.7-ROUTE/net/ipv4/netfilter/Makefile    2006-06-14 16:44:02.000000000 +0200
+@@ -74,6 +74,7 @@
+ obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.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_NETMAP) += ipt_NETMAP.o
+ obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
+ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+diff -u'rNF^function' linux-2.6.16.7/net/ipv4/netfilter/ipt_ROUTE.c linux-2.6.16.7-ROUTE/net/ipv4/netfilter/ipt_ROUTE.c
+--- linux-2.6.16.7/net/ipv4/netfilter/ipt_ROUTE.c       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7-ROUTE/net/ipv4/netfilter/ipt_ROUTE.c 2006-06-14 16:42:23.000000000 +0200
+@@ -0,0 +1,461 @@
++/*
++ * 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.11 2004/11/23
++ *
++ * 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/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ipt_ROUTE.h>
++#include <linux/netdevice.h>
++#include <linux/route.h>
++#include <linux/if_arp.h>
++#include <net/ip.h>
++#include <net/route.h>
++#include <net/icmp.h>
++#include <net/checksum.h>
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++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 :
++ *  - 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 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)
++               fl.fl4_dst = route_info->gw;
++
++       /* Trying to route the packet using the standard routing table. */
++       if ((err = ip_route_output_key(&rt, &fl))) {
++               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;
++               skb->protocol = htons(ETH_P_IP);
++               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;
++       struct net_device *dev = dst->dev;
++       int hh_len = LL_RESERVED_SPACE(dev);
++
++       /* Be paranoid, rather than too clever. */
++       if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
++               struct sk_buff *skb2;
++
++               skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
++               if (skb2 == NULL) {
++                       kfree_skb(skb);
++                       return;
++               }
++               if (skb->sk)
++                       skb_set_owner_w(skb2, skb->sk);
++               kfree_skb(skb);
++               skb = skb2;
++       }
++
++       if (hh) {
++               int hh_alen;
++
++               read_lock_bh(&hh->hh_lock);
++               hh_alen = HH_DATA_ALIGN(hh->hh_len);
++               memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
++               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_in = NULL;
++
++       /* Getting the current interface index. */
++       if (!(dev_in = dev_get_by_name(route_info->iif))) {
++               if (net_ratelimit())
++                       DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->iif);
++               return NF_DROP;
++       }
++
++       skb->dev = dev_in;
++       dst_release(skb->dst);
++       skb->dst = NULL;
++
++       netif_rx(skb);
++       dev_put(dev_in);
++       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;
++}
++
++
++/* To detect and deter routed packet loopback when using the --tee option,
++ * we take a page out of the raw.patch book: on the copied skb, we set up
++ * a fake ->nfct entry, pointing to the local &route_tee_track. We skip
++ * routing packets when we see they already have that ->nfct.
++ */
++
++static struct ip_conntrack route_tee_track;
++
++static unsigned int ipt_route_target(struct sk_buff **pskb,
++                                    const struct net_device *in,
++                                    const struct net_device *out,
++                                    unsigned int hooknum,
++                                    const void *targinfo,
++                                    void *userinfo)
++{
++       const struct ipt_route_target_info *route_info = targinfo;
++       struct sk_buff *skb = *pskb;
++       unsigned int res;
++
++       if (skb->nfct == &route_tee_track.ct_general) {
++               /* Loopback - a packet we already routed, is to be
++                * routed another time. Avoid that, now.
++                */
++               if (net_ratelimit())
++                       DEBUGP(KERN_DEBUG "ipt_ROUTE: loopback - DROP!\n");
++               return NF_DROP;
++       }
++
++       /* 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;
++                       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_key(&rt, &fl)) {
++                               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;
++               }
++
++               /*
++                * If we are at INPUT the checksum must be recalculated since
++                * the length could change as the result of a defragmentation.
++                */
++               if(hooknum == NF_IP_LOCAL_IN) {
++                       iph->ttl = iph->ttl - 1;
++                       iph->check = 0;
++                       iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
++               } else {
++                       ip_decrease_ttl(iph);
++               }
++       }
++
++       if ((route_info->flags & IPT_ROUTE_TEE)) {
++               /*
++                * Copy the *pskb, and route the copy. Will later return
++                * IPT_CONTINUE for the original skb, which should continue
++                * on its way as if nothing happened. The copy should be
++                * independantly delivered to the ROUTE --gw.
++                */
++               skb = skb_copy(*pskb, GFP_ATOMIC);
++               if (!skb) {
++                       if (net_ratelimit())
++                               DEBUGP(KERN_DEBUG "ipt_ROUTE: copy failed!\n");
++                       return IPT_CONTINUE;
++               }
++       }
++
++       /* 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.
++        *
++        * NEW: mark the skb with our &route_tee_track, so we avoid looping
++        * on any already routed packet.
++        */
++       if (!(route_info->flags & IPT_ROUTE_CONTINUE)) {
++               nf_conntrack_put(skb->nfct);
++               skb->nfct = &route_tee_track.ct_general;
++               skb->nfctinfo = IP_CT_NEW;
++               nf_conntrack_get(skb->nfct);
++       }
++
++       if (route_info->oif[0] != '\0') {
++               res = route_oif(route_info, skb);
++       } else if (route_info->iif[0] != '\0') {
++               res = route_iif(route_info, skb);
++       } else if (route_info->gw) {
++               res = route_gw(route_info, skb);
++       } else {
++               if (net_ratelimit())
++                       DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
++               res = IPT_CONTINUE;
++       }
++
++       if ((route_info->flags & IPT_ROUTE_TEE))
++               res = IPT_CONTINUE;
++
++       return res;
++}
++
++
++static int ipt_route_checkentry(const char *tablename,
++                               const void *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 = {
++       .name = "ROUTE",
++       .target = ipt_route_target,
++       .checkentry = ipt_route_checkentry,
++       .me = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++       /* Set up fake conntrack (stolen from raw.patch):
++           - to never be deleted, not in any hashes */
++       atomic_set(&route_tee_track.ct_general.use, 1);
++       /*  - and look it like as a confirmed connection */
++       set_bit(IPS_CONFIRMED_BIT, &route_tee_track.status);
++       /* Initialize fake conntrack so that NAT will skip it */
++       route_tee_track.status |= IPS_NAT_DONE_MASK;
++
++       return ipt_register_target(&ipt_route_reg);
++}
++
++
++static void __exit fini(void)
++{
++       ipt_unregister_target(&ipt_route_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -u'rNF^function' linux-2.6.16.7/net/ipv6/ipv6_syms.c linux-2.6.16.7-ROUTE/net/ipv6/ipv6_syms.c
+--- linux-2.6.16.7/net/ipv6/ipv6_syms.c 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7-ROUTE/net/ipv6/ipv6_syms.c   2006-06-14 17:02:32.000000000 +0200
+@@ -12,6 +12,7 @@
+ EXPORT_SYMBOL(icmpv6_statistics);
+ EXPORT_SYMBOL(icmpv6_err_convert);
+ EXPORT_SYMBOL(ndisc_mc_map);
++EXPORT_SYMBOL(nd_tbl);
+ EXPORT_SYMBOL(register_inet6addr_notifier);
+ EXPORT_SYMBOL(unregister_inet6addr_notifier);
+ EXPORT_SYMBOL(ip6_route_output);
+diff -u'rNF^function' linux-2.6.16.7/net/ipv6/netfilter/Kconfig linux-2.6.16.7-ROUTE/net/ipv6/netfilter/Kconfig
+--- linux-2.6.16.7/net/ipv6/netfilter/Kconfig   2006-06-14 16:05:44.000000000 +0200
++++ linux-2.6.16.7-ROUTE/net/ipv6/netfilter/Kconfig     2006-06-14 16:45:45.000000000 +0200
+@@ -182,6 +182,19 @@
+
+          To compile it as a module, choose M here.  If unsure, say N.
+
++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.
++
++          Not working as a module.
++
+ config IP6_NF_MANGLE
+        tristate "Packet mangling"
+        depends on IP6_NF_IPTABLES
+diff -u'rNF^function' linux-2.6.16.7/net/ipv6/netfilter/Makefile linux-2.6.16.7-ROUTE/net/ipv6/netfilter/Makefile
+--- linux-2.6.16.7/net/ipv6/netfilter/Makefile  2006-06-14 16:05:44.000000000 +0200
++++ linux-2.6.16.7-ROUTE/net/ipv6/netfilter/Makefile    2006-06-14 16:45:00.000000000 +0200
+@@ -22,6 +22,7 @@
+ obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
+ obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
+ obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
++obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o
+
+ # objects for l3 independent conntrack
+ nf_conntrack_ipv6-objs  :=  nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
+diff -u'rNF^function' linux-2.6.16.7/net/ipv6/netfilter/ip6t_ROUTE.c linux-2.6.16.7-ROUTE/net/ipv6/netfilter/ip6t_ROUTE.c
+--- linux-2.6.16.7/net/ipv6/netfilter/ip6t_ROUTE.c      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7-ROUTE/net/ipv6/netfilter/ip6t_ROUTE.c        2006-06-14 16:42:44.000000000 +0200
+@@ -0,0 +1,308 @@
++/*
++ * 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.1 2004/11/23
++ *
++ * 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,
++                 const struct net_device *in,
++                 const struct net_device *out,
++                 unsigned int hooknum,
++                 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;
++       unsigned int res;
++
++       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--;
++       }
++
++       if ((route_info->flags & IP6T_ROUTE_TEE)) {
++               /*
++                * Copy the *pskb, and route the copy. Will later return
++                * IP6T_CONTINUE for the original skb, which should continue
++                * on its way as if nothing happened. The copy should be
++                * independantly delivered to the ROUTE --gw.
++                */
++               skb = skb_copy(*pskb, GFP_ATOMIC);
++               if (!skb) {
++                       if (net_ratelimit())
++                               DEBUGP(KERN_DEBUG "ip6t_ROUTE: copy failed!\n");
++                       return IP6T_CONTINUE;
++               }
++       }
++
++do_it:
++       if (route_info->oif[0]) {
++               res = route6_oif(route_info, skb);
++       } else if (!ipv6_addr_any(gw)) {
++               res = route6_gw(route_info, skb);
++       } else {
++               if (net_ratelimit())
++                       DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
++               res = IP6T_CONTINUE;
++       }
++
++       if ((route_info->flags & IP6T_ROUTE_TEE))
++               res = IP6T_CONTINUE;
++
++       return res;
++}
++
++
++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");
index 6921ad5a446be67d6bb6bf6a4c19803b3b7758a9..eaa3771d11de1d36724181ffd15a218e2816b7dc 100644 (file)
@@ -381,6 +381,7 @@ CONFIG_IP_NF_NAT=y
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
 # CONFIG_IP_NF_TARGET_NETMAP is not set
 # CONFIG_IP_NF_TARGET_SAME is not set
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
@@ -428,6 +429,7 @@ CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_IMQ=m
 # CONFIG_IP6_NF_TARGET_LOG is not set
 CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
 CONFIG_IP6_NF_MANGLE=m
 # CONFIG_IP6_NF_TARGET_HL is not set
 # CONFIG_IP6_NF_RAW is not set
index 5e055acaf73f0d4b070e929ab85235fbdd76ad4c..79c4c72f068039c0889e09226fa335dbca06e93a 100644 (file)
@@ -394,6 +394,7 @@ CONFIG_IP_NF_NAT=y
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
 # CONFIG_IP_NF_TARGET_NETMAP is not set
 # CONFIG_IP_NF_TARGET_SAME is not set
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
@@ -442,6 +443,7 @@ CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_IMQ=m
 # CONFIG_IP6_NF_TARGET_LOG is not set
 CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
 CONFIG_IP6_NF_MANGLE=m
 # CONFIG_IP6_NF_TARGET_HL is not set
 # CONFIG_IP6_NF_RAW is not set
index 0e675c1e0d9d945619a7edee4c64acf79abca834..4480a0120d99396db178031f4935c86cb41c0553 100644 (file)
@@ -357,6 +357,7 @@ CONFIG_IP_NF_NAT=y
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_ROUTE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
 CONFIG_IP_NF_TARGET_SAME=m
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
@@ -406,6 +407,7 @@ CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_IMQ=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
index 626716c0cd474d592445b5828b0c88529034f127..fee9c753454ec03a4edd6975dae6de9b4ab0904a 100644 (file)
@@ -423,6 +423,7 @@ CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_ROUTE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
 CONFIG_IP_NF_TARGET_SAME=m
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
@@ -472,6 +473,7 @@ CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_IMQ=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
index 4eac5f9b269ecb6608282b3f8831e9d27e3b481a..74a56554b59f41014e9c458d0fd53ec05b88951e 100644 (file)
@@ -348,6 +348,7 @@ CONFIG_IP_NF_NAT=y
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
 CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_ROUTE=m
 # CONFIG_IP_NF_TARGET_NETMAP is not set
 # CONFIG_IP_NF_TARGET_SAME is not set
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
@@ -381,6 +382,7 @@ CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_FILTER=m
 # CONFIG_IP6_NF_TARGET_LOG is not set
 CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
 # CONFIG_IP6_NF_MANGLE is not set
 # CONFIG_IP6_NF_RAW is not set