1 include/linux/netfilter_ipv4/ipt_ROUTE.h | 23 +
2 include/linux/netfilter_ipv6/ip6t_ROUTE.h | 23 +
3 net/ipv4/netfilter/Kconfig | 17 +
4 net/ipv4/netfilter/Makefile | 1
5 net/ipv4/netfilter/ipt_ROUTE.c | 464 ++++++++++++++++++++++++++++++
6 net/ipv6/ipv6_syms.c | 1
7 net/ipv6/netfilter/Kconfig | 13
8 net/ipv6/netfilter/Makefile | 1
9 net/ipv6/netfilter/ip6t_ROUTE.c | 311 ++++++++++++++++++++
10 9 files changed, 854 insertions(+)
12 diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv4/ipt_ROUTE.h linux/include/linux/netfilter_ipv4/ipt_ROUTE.h
13 --- linux.org/include/linux/netfilter_ipv4/ipt_ROUTE.h 1970-01-01 00:00:00.000000000 +0000
14 +++ linux/include/linux/netfilter_ipv4/ipt_ROUTE.h 2006-08-29 12:03:16.000000000 +0000
16 +/* Header file for iptables ipt_ROUTE target
18 + * (C) 2002 by Cédric de Launois <delaunois@info.ucl.ac.be>
20 + * This software is distributed under GNU GPL v2, 1991
22 +#ifndef _IPT_ROUTE_H_target
23 +#define _IPT_ROUTE_H_target
25 +#define IPT_ROUTE_IFNAMSIZ 16
27 +struct ipt_route_target_info {
28 + char oif[IPT_ROUTE_IFNAMSIZ]; /* Output Interface Name */
29 + char iif[IPT_ROUTE_IFNAMSIZ]; /* Input Interface Name */
30 + u_int32_t gw; /* IP address of gateway */
34 +/* Values for "flags" field */
35 +#define IPT_ROUTE_CONTINUE 0x01
36 +#define IPT_ROUTE_TEE 0x02
38 +#endif /*_IPT_ROUTE_H_target*/
39 diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h
40 --- linux.org/include/linux/netfilter_ipv6/ip6t_ROUTE.h 1970-01-01 00:00:00.000000000 +0000
41 +++ linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h 2006-08-29 12:03:16.000000000 +0000
43 +/* Header file for iptables ip6t_ROUTE target
45 + * (C) 2003 by Cédric de Launois <delaunois@info.ucl.ac.be>
47 + * This software is distributed under GNU GPL v2, 1991
49 +#ifndef _IPT_ROUTE_H_target
50 +#define _IPT_ROUTE_H_target
52 +#define IP6T_ROUTE_IFNAMSIZ 16
54 +struct ip6t_route_target_info {
55 + char oif[IP6T_ROUTE_IFNAMSIZ]; /* Output Interface Name */
56 + char iif[IP6T_ROUTE_IFNAMSIZ]; /* Input Interface Name */
57 + u_int32_t gw[4]; /* IPv6 address of gateway */
61 +/* Values for "flags" field */
62 +#define IP6T_ROUTE_CONTINUE 0x01
63 +#define IP6T_ROUTE_TEE 0x02
65 +#endif /*_IP6T_ROUTE_H_target*/
66 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_ROUTE.c linux/net/ipv4/netfilter/ipt_ROUTE.c
67 --- linux.org/net/ipv4/netfilter/ipt_ROUTE.c 1970-01-01 00:00:00.000000000 +0000
68 +++ linux/net/ipv4/netfilter/ipt_ROUTE.c 2006-08-29 12:03:16.000000000 +0000
71 + * This implements the ROUTE target, which enables you to setup unusual
72 + * routes not supported by the standard kernel routing table.
74 + * Copyright (C) 2002 Cedric de Launois <delaunois@info.ucl.ac.be>
78 + * This software is distributed under GNU GPL v2, 1991
81 +#include <linux/module.h>
82 +#include <linux/skbuff.h>
83 +#include <linux/ip.h>
84 +#include <linux/netfilter_ipv4/ip_tables.h>
85 +#include <linux/netfilter_ipv4/ip_conntrack.h>
86 +#include <linux/netfilter_ipv4/ipt_ROUTE.h>
87 +#include <linux/netdevice.h>
88 +#include <linux/route.h>
89 +#include <linux/if_arp.h>
91 +#include <net/route.h>
92 +#include <net/icmp.h>
93 +#include <net/checksum.h>
96 +#define DEBUGP printk
98 +#define DEBUGP(format, args...)
101 +MODULE_LICENSE("GPL");
102 +MODULE_AUTHOR("Cedric de Launois <delaunois@info.ucl.ac.be>");
103 +MODULE_DESCRIPTION("iptables ROUTE target module");
105 +/* Try to route the packet according to the routing keys specified in
106 + * route_info. Keys are :
108 + * 0 if no oif preferred,
109 + * otherwise set to the index of the desired oif
110 + * - route_info->gw :
111 + * 0 if no gateway specified,
112 + * otherwise set to the next host to which the pkt must be routed
113 + * If success, skb->dev is the output device to which the packet must
114 + * be sent and skb->dst is not NULL
116 + * RETURN: -1 if an error occured
117 + * 1 if the packet was succesfully routed to the
118 + * destination desired
119 + * 0 if the kernel routing table could not route the packet
120 + * according to the keys specified
122 +static int route(struct sk_buff *skb,
123 + unsigned int ifindex,
124 + const struct ipt_route_target_info *route_info)
128 + struct iphdr *iph = skb->nh.iph;
129 + struct flowi fl = {
133 + .daddr = iph->daddr,
135 + .tos = RT_TOS(iph->tos),
136 + .scope = RT_SCOPE_UNIVERSE,
141 + /* The destination address may be overloaded by the target */
142 + if (route_info->gw)
143 + fl.fl4_dst = route_info->gw;
145 + /* Trying to route the packet using the standard routing table. */
146 + if ((err = ip_route_output_key(&rt, &fl))) {
147 + if (net_ratelimit())
148 + DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err);
152 + /* Drop old route. */
153 + dst_release(skb->dst);
156 + /* Success if no oif specified or if the oif correspond to the
158 + if (!ifindex || rt->u.dst.dev->ifindex == ifindex) {
159 + skb->dst = &rt->u.dst;
160 + skb->dev = skb->dst->dev;
161 + skb->protocol = htons(ETH_P_IP);
165 + /* The interface selected by the routing table is not the one
166 + * specified by the user. This may happen because the dst address
167 + * is one of our own addresses.
169 + if (net_ratelimit())
170 + DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n",
171 + NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex);
177 +/* Stolen from ip_finish_output2
178 + * PRE : skb->dev is set to the device we are leaving by
179 + * skb->dst is not NULL
180 + * POST: the packet is sent with the link layer header pushed
181 + * the packet is destroyed
183 +static void ip_direct_send(struct sk_buff *skb)
185 + struct dst_entry *dst = skb->dst;
186 + struct hh_cache *hh = dst->hh;
187 + struct net_device *dev = dst->dev;
188 + int hh_len = LL_RESERVED_SPACE(dev);
190 + /* Be paranoid, rather than too clever. */
191 + if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
192 + struct sk_buff *skb2;
194 + skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
195 + if (skb2 == NULL) {
200 + skb_set_owner_w(skb2, skb->sk);
208 + read_lock_bh(&hh->hh_lock);
209 + hh_alen = HH_DATA_ALIGN(hh->hh_len);
210 + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
211 + read_unlock_bh(&hh->hh_lock);
212 + skb_push(skb, hh->hh_len);
213 + hh->hh_output(skb);
214 + } else if (dst->neighbour)
215 + dst->neighbour->output(skb);
217 + if (net_ratelimit())
218 + DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n");
224 +/* PRE : skb->dev is set to the device we are leaving by
225 + * POST: - the packet is directly sent to the skb->dev device, without
226 + * pushing the link layer header.
227 + * - the packet is destroyed
229 +static inline int dev_direct_send(struct sk_buff *skb)
231 + return dev_queue_xmit(skb);
235 +static unsigned int route_oif(const struct ipt_route_target_info *route_info,
236 + struct sk_buff *skb)
238 + unsigned int ifindex = 0;
239 + struct net_device *dev_out = NULL;
241 + /* The user set the interface name to use.
242 + * Getting the current interface index.
244 + if ((dev_out = dev_get_by_name(route_info->oif))) {
245 + ifindex = dev_out->ifindex;
247 + /* Unknown interface name : packet dropped */
248 + if (net_ratelimit())
249 + DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif);
253 + /* Trying the standard way of routing packets */
254 + switch (route(skb, ifindex, route_info)) {
257 + if (route_info->flags & IPT_ROUTE_CONTINUE)
258 + return IPT_CONTINUE;
260 + ip_direct_send(skb);
264 + /* Failed to send to oif. Trying the hard way */
265 + if (route_info->flags & IPT_ROUTE_CONTINUE)
268 + if (net_ratelimit())
269 + DEBUGP("ipt_ROUTE: forcing the use of %i\n",
272 + /* We have to force the use of an interface.
273 + * This interface must be a tunnel interface since
274 + * otherwise we can't guess the hw address for
275 + * the packet. For a tunnel interface, no hw address
278 + if ((dev_out->type != ARPHRD_TUNNEL)
279 + && (dev_out->type != ARPHRD_IPGRE)) {
280 + if (net_ratelimit())
281 + DEBUGP("ipt_ROUTE: can't guess the hw addr !\n");
286 + /* Send the packet. This will also free skb
287 + * Do not go through the POST_ROUTING hook because
288 + * skb->dst is not set and because it will probably
289 + * get confused by the destination IP address.
291 + skb->dev = dev_out;
292 + dev_direct_send(skb);
297 + /* Unexpected error */
304 +static unsigned int route_iif(const struct ipt_route_target_info *route_info,
305 + struct sk_buff *skb)
307 + struct net_device *dev_in = NULL;
309 + /* Getting the current interface index. */
310 + if (!(dev_in = dev_get_by_name(route_info->iif))) {
311 + if (net_ratelimit())
312 + DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->iif);
317 + dst_release(skb->dst);
326 +static unsigned int route_gw(const struct ipt_route_target_info *route_info,
327 + struct sk_buff *skb)
329 + if (route(skb, 0, route_info)!=1)
332 + if (route_info->flags & IPT_ROUTE_CONTINUE)
333 + return IPT_CONTINUE;
335 + ip_direct_send(skb);
340 +/* To detect and deter routed packet loopback when using the --tee option,
341 + * we take a page out of the raw.patch book: on the copied skb, we set up
342 + * a fake ->nfct entry, pointing to the local &route_tee_track. We skip
343 + * routing packets when we see they already have that ->nfct.
346 +static struct ip_conntrack route_tee_track;
348 +static unsigned int ipt_route_target(struct sk_buff **pskb,
349 + const struct net_device *in,
350 + const struct net_device *out,
351 + unsigned int hooknum,
352 + const struct xt_target *target,
353 + const void *targinfo,
356 + const struct ipt_route_target_info *route_info = targinfo;
357 + struct sk_buff *skb = *pskb;
360 + if (skb->nfct == &route_tee_track.ct_general) {
361 + /* Loopback - a packet we already routed, is to be
362 + * routed another time. Avoid that, now.
364 + if (net_ratelimit())
365 + DEBUGP(KERN_DEBUG "ipt_ROUTE: loopback - DROP!\n");
369 + /* If we are at PREROUTING or INPUT hook
370 + * the TTL isn't decreased by the IP stack
372 + if (hooknum == NF_IP_PRE_ROUTING ||
373 + hooknum == NF_IP_LOCAL_IN) {
375 + struct iphdr *iph = skb->nh.iph;
377 + if (iph->ttl <= 1) {
379 + struct flowi fl = {
383 + .daddr = iph->daddr,
384 + .saddr = iph->saddr,
385 + .tos = RT_TOS(iph->tos),
386 + .scope = ((iph->tos & RTO_ONLINK) ?
393 + if (ip_route_output_key(&rt, &fl)) {
397 + if (skb->dev == rt->u.dst.dev) {
398 + /* Drop old route. */
399 + dst_release(skb->dst);
400 + skb->dst = &rt->u.dst;
402 + /* this will traverse normal stack, and
403 + * thus call conntrack on the icmp packet */
404 + icmp_send(skb, ICMP_TIME_EXCEEDED,
412 + * If we are at INPUT the checksum must be recalculated since
413 + * the length could change as the result of a defragmentation.
415 + if(hooknum == NF_IP_LOCAL_IN) {
416 + iph->ttl = iph->ttl - 1;
418 + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
420 + ip_decrease_ttl(iph);
424 + if ((route_info->flags & IPT_ROUTE_TEE)) {
426 + * Copy the *pskb, and route the copy. Will later return
427 + * IPT_CONTINUE for the original skb, which should continue
428 + * on its way as if nothing happened. The copy should be
429 + * independantly delivered to the ROUTE --gw.
431 + skb = skb_copy(*pskb, GFP_ATOMIC);
433 + if (net_ratelimit())
434 + DEBUGP(KERN_DEBUG "ipt_ROUTE: copy failed!\n");
435 + return IPT_CONTINUE;
439 + /* Tell conntrack to forget this packet since it may get confused
440 + * when a packet is leaving with dst address == our address.
441 + * Good idea ? Dunno. Need advice.
443 + * NEW: mark the skb with our &route_tee_track, so we avoid looping
444 + * on any already routed packet.
446 + if (!(route_info->flags & IPT_ROUTE_CONTINUE)) {
447 + nf_conntrack_put(skb->nfct);
448 + skb->nfct = &route_tee_track.ct_general;
449 + skb->nfctinfo = IP_CT_NEW;
450 + nf_conntrack_get(skb->nfct);
453 + if (route_info->oif[0] != '\0') {
454 + res = route_oif(route_info, skb);
455 + } else if (route_info->iif[0] != '\0') {
456 + res = route_iif(route_info, skb);
457 + } else if (route_info->gw) {
458 + res = route_gw(route_info, skb);
460 + if (net_ratelimit())
461 + DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
462 + res = IPT_CONTINUE;
465 + if ((route_info->flags & IPT_ROUTE_TEE))
466 + res = IPT_CONTINUE;
472 +static int ipt_route_checkentry(const char *tablename,
474 + const struct xt_target *target,
476 + unsigned int targinfosize,
477 + unsigned int hook_mask)
479 + if (strcmp(tablename, "mangle") != 0) {
480 + printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n",
485 + if (hook_mask & ~( (1 << NF_IP_PRE_ROUTING)
486 + | (1 << NF_IP_LOCAL_IN)
487 + | (1 << NF_IP_FORWARD)
488 + | (1 << NF_IP_LOCAL_OUT)
489 + | (1 << NF_IP_POST_ROUTING))) {
490 + printk("ipt_ROUTE: bad hook\n");
494 + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) {
495 + printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n",
497 + IPT_ALIGN(sizeof(struct ipt_route_target_info)));
505 +static struct ipt_target ipt_route_reg = {
507 + .target = ipt_route_target,
508 + .targetsize = sizeof(struct ipt_route_target_info),
509 + .checkentry = ipt_route_checkentry,
513 +static int __init init(void)
515 + /* Set up fake conntrack (stolen from raw.patch):
516 + - to never be deleted, not in any hashes */
517 + atomic_set(&route_tee_track.ct_general.use, 1);
518 + /* - and look it like as a confirmed connection */
519 + set_bit(IPS_CONFIRMED_BIT, &route_tee_track.status);
520 + /* Initialize fake conntrack so that NAT will skip it */
521 + route_tee_track.status |= IPS_NAT_DONE_MASK;
523 + return ipt_register_target(&ipt_route_reg);
527 +static void __exit fini(void)
529 + ipt_unregister_target(&ipt_route_reg);
534 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig
535 --- linux.org/net/ipv4/netfilter/Kconfig 2006-06-18 01:49:35.000000000 +0000
536 +++ linux/net/ipv4/netfilter/Kconfig 2006-08-29 12:03:16.000000000 +0000
538 Allows altering the ARP packet payload: source and destination
539 hardware and network addresses.
541 +config IP_NF_TARGET_ROUTE
542 + tristate 'ROUTE target support'
543 + depends on IP_NF_MANGLE
545 + This option adds a `ROUTE' target, which enables you to setup unusual
546 + routes. For example, the ROUTE lets you route a received packet through
547 + an interface or towards a host, even if the regular destination of the
548 + packet is the router itself. The ROUTE target is also able to change the
549 + incoming interface of a packet.
551 + The target can be or not a final target. It has to be used inside the
554 + If you want to compile it as a module, say M here and read
555 + Documentation/modules.txt. The module will be called ipt_ROUTE.o.
556 + If unsure, say `N'.
560 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
561 --- linux.org/net/ipv4/netfilter/Makefile 2006-06-18 01:49:35.000000000 +0000
562 +++ linux/net/ipv4/netfilter/Makefile 2006-08-29 12:03:16.000000000 +0000
564 +obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o
565 diff -Nur --exclude '*.orig' linux.org/net/ipv6/ipv6_syms.c linux/net/ipv6/ipv6_syms.c
566 --- linux.org/net/ipv6/ipv6_syms.c 2006-06-18 01:49:35.000000000 +0000
567 +++ linux/net/ipv6/ipv6_syms.c 2006-08-29 12:03:16.000000000 +0000
569 EXPORT_SYMBOL(icmpv6_statistics);
570 EXPORT_SYMBOL(icmpv6_err_convert);
571 EXPORT_SYMBOL(ndisc_mc_map);
572 +EXPORT_SYMBOL(nd_tbl);
573 EXPORT_SYMBOL(register_inet6addr_notifier);
574 EXPORT_SYMBOL(unregister_inet6addr_notifier);
575 EXPORT_SYMBOL(ip6_route_output);
576 diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/ip6t_ROUTE.c linux/net/ipv6/netfilter/ip6t_ROUTE.c
577 --- linux.org/net/ipv6/netfilter/ip6t_ROUTE.c 1970-01-01 00:00:00.000000000 +0000
578 +++ linux/net/ipv6/netfilter/ip6t_ROUTE.c 2006-08-29 12:03:16.000000000 +0000
581 + * This implements the ROUTE v6 target, which enables you to setup unusual
582 + * routes not supported by the standard kernel routing table.
584 + * Copyright (C) 2003 Cedric de Launois <delaunois@info.ucl.ac.be>
588 + * This software is distributed under GNU GPL v2, 1991
591 +#include <linux/module.h>
592 +#include <linux/skbuff.h>
593 +#include <linux/ipv6.h>
594 +#include <linux/netfilter_ipv6/ip6_tables.h>
595 +#include <linux/netfilter_ipv6/ip6t_ROUTE.h>
596 +#include <linux/netdevice.h>
597 +#include <net/ipv6.h>
598 +#include <net/ndisc.h>
599 +#include <net/ip6_route.h>
600 +#include <linux/icmpv6.h>
603 +#define DEBUGP printk
605 +#define DEBUGP(format, args...)
608 +#define NIP6(addr) \
609 + ntohs((addr).s6_addr16[0]), \
610 + ntohs((addr).s6_addr16[1]), \
611 + ntohs((addr).s6_addr16[2]), \
612 + ntohs((addr).s6_addr16[3]), \
613 + ntohs((addr).s6_addr16[4]), \
614 + ntohs((addr).s6_addr16[5]), \
615 + ntohs((addr).s6_addr16[6]), \
616 + ntohs((addr).s6_addr16[7])
618 +/* Route the packet according to the routing keys specified in
619 + * route_info. Keys are :
621 + * 0 if no oif preferred,
622 + * otherwise set to the index of the desired oif
623 + * - route_info->gw :
624 + * 0 if no gateway specified,
625 + * otherwise set to the next host to which the pkt must be routed
626 + * If success, skb->dev is the output device to which the packet must
627 + * be sent and skb->dst is not NULL
629 + * RETURN: 1 if the packet was succesfully routed to the
630 + * destination desired
631 + * 0 if the kernel routing table could not route the packet
632 + * according to the keys specified
635 +route6(struct sk_buff *skb,
636 + unsigned int ifindex,
637 + const struct ip6t_route_target_info *route_info)
639 + struct rt6_info *rt = NULL;
640 + struct ipv6hdr *ipv6h = skb->nh.ipv6h;
641 + struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
643 + DEBUGP("ip6t_ROUTE: called with: ");
644 + DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
645 + DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
646 + DEBUGP("OUT=%s\n", route_info->oif);
648 + if (ipv6_addr_any(gw))
649 + rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
651 + rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
656 + DEBUGP("ip6t_ROUTE: routing gives: ");
657 + DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
658 + DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
659 + DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
661 + if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
664 + if (!rt->rt6i_nexthop) {
665 + DEBUGP("ip6t_ROUTE: discovering neighbour\n");
666 + rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
669 + /* Drop old route. */
670 + dst_release(skb->dst);
671 + skb->dst = &rt->u.dst;
672 + skb->dev = rt->rt6i_dev;
676 + dst_release(&rt->u.dst);
678 + if (!net_ratelimit())
681 + printk("ip6t_ROUTE: no explicit route found ");
683 + printk("via interface %s ", route_info->oif);
684 + if (!ipv6_addr_any(gw))
685 + printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
691 +/* Stolen from ip6_output_finish
692 + * PRE : skb->dev is set to the device we are leaving by
693 + * skb->dst is not NULL
694 + * POST: the packet is sent with the link layer header pushed
695 + * the packet is destroyed
697 +static void ip_direct_send(struct sk_buff *skb)
699 + struct dst_entry *dst = skb->dst;
700 + struct hh_cache *hh = dst->hh;
703 + read_lock_bh(&hh->hh_lock);
704 + memcpy(skb->data - 16, hh->hh_data, 16);
705 + read_unlock_bh(&hh->hh_lock);
706 + skb_push(skb, hh->hh_len);
707 + hh->hh_output(skb);
708 + } else if (dst->neighbour)
709 + dst->neighbour->output(skb);
711 + if (net_ratelimit())
712 + DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n");
719 +route6_oif(const struct ip6t_route_target_info *route_info,
720 + struct sk_buff *skb)
722 + unsigned int ifindex = 0;
723 + struct net_device *dev_out = NULL;
725 + /* The user set the interface name to use.
726 + * Getting the current interface index.
728 + if ((dev_out = dev_get_by_name(route_info->oif))) {
729 + ifindex = dev_out->ifindex;
731 + /* Unknown interface name : packet dropped */
732 + if (net_ratelimit())
733 + DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
735 + if (route_info->flags & IP6T_ROUTE_CONTINUE)
736 + return IP6T_CONTINUE;
741 + /* Trying the standard way of routing packets */
742 + if (route6(skb, ifindex, route_info)) {
744 + if (route_info->flags & IP6T_ROUTE_CONTINUE)
745 + return IP6T_CONTINUE;
747 + ip_direct_send(skb);
755 +route6_gw(const struct ip6t_route_target_info *route_info,
756 + struct sk_buff *skb)
758 + if (route6(skb, 0, route_info)) {
759 + if (route_info->flags & IP6T_ROUTE_CONTINUE)
760 + return IP6T_CONTINUE;
762 + ip_direct_send(skb);
770 +ip6t_route_target(struct sk_buff **pskb,
771 + const struct net_device *in,
772 + const struct net_device *out,
773 + unsigned int hooknum,
774 + const struct xt_target *target,
775 + const void *targinfo,
778 + const struct ip6t_route_target_info *route_info = targinfo;
779 + struct sk_buff *skb = *pskb;
780 + struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
783 + if (route_info->flags & IP6T_ROUTE_CONTINUE)
786 + /* If we are at PREROUTING or INPUT hook
787 + * the TTL isn't decreased by the IP stack
789 + if (hooknum == NF_IP6_PRE_ROUTING ||
790 + hooknum == NF_IP6_LOCAL_IN) {
792 + struct ipv6hdr *ipv6h = skb->nh.ipv6h;
794 + if (ipv6h->hop_limit <= 1) {
795 + /* Force OUTPUT device used as source address */
796 + skb->dev = skb->dst->dev;
798 + icmpv6_send(skb, ICMPV6_TIME_EXCEED,
799 + ICMPV6_EXC_HOPLIMIT, 0, skb->dev);
804 + ipv6h->hop_limit--;
807 + if ((route_info->flags & IP6T_ROUTE_TEE)) {
809 + * Copy the *pskb, and route the copy. Will later return
810 + * IP6T_CONTINUE for the original skb, which should continue
811 + * on its way as if nothing happened. The copy should be
812 + * independantly delivered to the ROUTE --gw.
814 + skb = skb_copy(*pskb, GFP_ATOMIC);
816 + if (net_ratelimit())
817 + DEBUGP(KERN_DEBUG "ip6t_ROUTE: copy failed!\n");
818 + return IP6T_CONTINUE;
823 + if (route_info->oif[0]) {
824 + res = route6_oif(route_info, skb);
825 + } else if (!ipv6_addr_any(gw)) {
826 + res = route6_gw(route_info, skb);
828 + if (net_ratelimit())
829 + DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
830 + res = IP6T_CONTINUE;
833 + if ((route_info->flags & IP6T_ROUTE_TEE))
834 + res = IP6T_CONTINUE;
841 +ip6t_route_checkentry(const char *tablename,
843 + const struct xt_target *target,
845 + unsigned int targinfosize,
846 + unsigned int hook_mask)
848 + if (strcmp(tablename, "mangle") != 0) {
849 + printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
853 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) {
854 + printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n",
856 + IP6T_ALIGN(sizeof(struct ip6t_route_target_info)));
864 +static struct ip6t_target ip6t_route_reg = {
866 + .target = ip6t_route_target,
867 + .targetsize = sizeof(struct ip6t_route_target_info),
868 + .checkentry = ip6t_route_checkentry,
873 +static int __init init(void)
875 + printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
876 + if (ip6t_register_target(&ip6t_route_reg))
883 +static void __exit fini(void)
885 + ip6t_unregister_target(&ip6t_route_reg);
890 +MODULE_LICENSE("GPL");
891 diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/Kconfig linux/net/ipv6/netfilter/Kconfig
892 --- linux.org/net/ipv6/netfilter/Kconfig 2006-06-18 01:49:35.000000000 +0000
893 +++ linux/net/ipv6/netfilter/Kconfig 2006-08-29 12:03:16.000000000 +0000
895 If you want to compile it as a module, say M here and read
896 <file:Documentation/modules.txt>. If unsure, say `N'.
898 +config IP6_NF_TARGET_ROUTE
899 + tristate ' ROUTE target support'
900 + depends on IP6_NF_MANGLE
902 + This option adds a `ROUTE' target, which enables you to setup unusual
903 + routes. The ROUTE target is also able to change the incoming interface
906 + The target can be or not a final target. It has to be used inside the
909 + Not working as a module.
913 diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/Makefile linux/net/ipv6/netfilter/Makefile
914 --- linux.org/net/ipv6/netfilter/Makefile 2006-06-18 01:49:35.000000000 +0000
915 +++ linux/net/ipv6/netfilter/Makefile 2006-08-29 12:03:16.000000000 +0000
917 +obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o