|
|
|
@ -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");
|