add thermal symbol to the generic .25 config
[openwrt.git] / target / linux / generic-2.6 / patches-2.6.21 / 160-netfilter_route.patch
1 Index: linux-2.6.21.7/include/linux/netfilter_ipv4/ipt_ROUTE.h
2 ===================================================================
3 --- /dev/null
4 +++ linux-2.6.21.7/include/linux/netfilter_ipv4/ipt_ROUTE.h
5 @@ -0,0 +1,23 @@
6 +/* Header file for iptables ipt_ROUTE target
7 + *
8 + * (C) 2002 by Cédric de Launois <delaunois@info.ucl.ac.be>
9 + *
10 + * This software is distributed under GNU GPL v2, 1991
11 + */
12 +#ifndef _IPT_ROUTE_H_target
13 +#define _IPT_ROUTE_H_target
14 +
15 +#define IPT_ROUTE_IFNAMSIZ 16
16 +
17 +struct ipt_route_target_info {
18 +       char      oif[IPT_ROUTE_IFNAMSIZ];      /* Output Interface Name */
19 +       char      iif[IPT_ROUTE_IFNAMSIZ];      /* Input Interface Name  */
20 +       u_int32_t gw;                           /* IP address of gateway */
21 +       u_int8_t  flags;
22 +};
23 +
24 +/* Values for "flags" field */
25 +#define IPT_ROUTE_CONTINUE        0x01
26 +#define IPT_ROUTE_TEE             0x02
27 +
28 +#endif /*_IPT_ROUTE_H_target*/
29 Index: linux-2.6.21.7/include/linux/netfilter_ipv6/ip6t_ROUTE.h
30 ===================================================================
31 --- /dev/null
32 +++ linux-2.6.21.7/include/linux/netfilter_ipv6/ip6t_ROUTE.h
33 @@ -0,0 +1,23 @@
34 +/* Header file for iptables ip6t_ROUTE target
35 + *
36 + * (C) 2003 by Cédric de Launois <delaunois@info.ucl.ac.be>
37 + *
38 + * This software is distributed under GNU GPL v2, 1991
39 + */
40 +#ifndef _IPT_ROUTE_H_target
41 +#define _IPT_ROUTE_H_target
42 +
43 +#define IP6T_ROUTE_IFNAMSIZ 16
44 +
45 +struct ip6t_route_target_info {
46 +       char      oif[IP6T_ROUTE_IFNAMSIZ];     /* Output Interface Name */
47 +       char      iif[IP6T_ROUTE_IFNAMSIZ];     /* Input Interface Name  */
48 +       u_int32_t gw[4];                        /* IPv6 address of gateway */
49 +       u_int8_t  flags;
50 +};
51 +
52 +/* Values for "flags" field */
53 +#define IP6T_ROUTE_CONTINUE        0x01
54 +#define IP6T_ROUTE_TEE             0x02
55 +
56 +#endif /*_IP6T_ROUTE_H_target*/
57 Index: linux-2.6.21.7/net/ipv4/netfilter/ipt_ROUTE.c
58 ===================================================================
59 --- /dev/null
60 +++ linux-2.6.21.7/net/ipv4/netfilter/ipt_ROUTE.c
61 @@ -0,0 +1,483 @@
62 +/*
63 + * This implements the ROUTE target, which enables you to setup unusual
64 + * routes not supported by the standard kernel routing table.
65 + *
66 + * Copyright (C) 2002 Cedric de Launois <delaunois@info.ucl.ac.be>
67 + *
68 + * v 1.11 2004/11/23
69 + *
70 + * This software is distributed under GNU GPL v2, 1991
71 + */
72 +
73 +#include <linux/module.h>
74 +#include <linux/skbuff.h>
75 +#include <linux/ip.h>
76 +#include <linux/netfilter_ipv4/ip_tables.h>
77 +#include <linux/netfilter_ipv4/ip_conntrack.h>
78 +#include <linux/netfilter_ipv4/ipt_ROUTE.h>
79 +#include <linux/netdevice.h>
80 +#include <linux/route.h>
81 +#include <linux/version.h>
82 +#include <linux/if_arp.h>
83 +#include <net/ip.h>
84 +#include <net/route.h>
85 +#include <net/icmp.h>
86 +#include <net/checksum.h>
87 +
88 +#if 0
89 +#define DEBUGP printk
90 +#else
91 +#define DEBUGP(format, args...)
92 +#endif
93 +
94 +MODULE_LICENSE("GPL");
95 +MODULE_AUTHOR("Cedric de Launois <delaunois@info.ucl.ac.be>");
96 +MODULE_DESCRIPTION("iptables ROUTE target module");
97 +
98 +/* Try to route the packet according to the routing keys specified in
99 + * route_info. Keys are :
100 + *  - ifindex : 
101 + *      0 if no oif preferred, 
102 + *      otherwise set to the index of the desired oif
103 + *  - route_info->gw :
104 + *      0 if no gateway specified,
105 + *      otherwise set to the next host to which the pkt must be routed
106 + * If success, skb->dev is the output device to which the packet must 
107 + * be sent and skb->dst is not NULL
108 + *
109 + * RETURN: -1 if an error occured
110 + *          1 if the packet was succesfully routed to the 
111 + *            destination desired
112 + *          0 if the kernel routing table could not route the packet
113 + *            according to the keys specified
114 + */
115 +static int route(struct sk_buff *skb,
116 +                unsigned int ifindex,
117 +                const struct ipt_route_target_info *route_info)
118 +{
119 +       int err;
120 +       struct rtable *rt;
121 +       struct iphdr *iph = skb->nh.iph;
122 +       struct flowi fl = {
123 +               .oif = ifindex,
124 +               .nl_u = {
125 +                       .ip4_u = {
126 +                               .daddr = iph->daddr,
127 +                               .saddr = 0,
128 +                               .tos = RT_TOS(iph->tos),
129 +                               .scope = RT_SCOPE_UNIVERSE,
130 +                       }
131 +               } 
132 +       };
133 +       
134 +       /* The destination address may be overloaded by the target */
135 +       if (route_info->gw)
136 +               fl.fl4_dst = route_info->gw;
137 +       
138 +       /* Trying to route the packet using the standard routing table. */
139 +       if ((err = ip_route_output_key(&rt, &fl))) {
140 +               if (net_ratelimit()) 
141 +                       DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err);
142 +               return -1;
143 +       }
144 +       
145 +       /* Drop old route. */
146 +       dst_release(skb->dst);
147 +       skb->dst = NULL;
148 +
149 +       /* Success if no oif specified or if the oif correspond to the 
150 +        * one desired */
151 +       if (!ifindex || rt->u.dst.dev->ifindex == ifindex) {
152 +               skb->dst = &rt->u.dst;
153 +               skb->dev = skb->dst->dev;
154 +               skb->protocol = htons(ETH_P_IP);
155 +               return 1;
156 +       }
157 +       
158 +       /* The interface selected by the routing table is not the one
159 +        * specified by the user. This may happen because the dst address
160 +        * is one of our own addresses.
161 +        */
162 +       if (net_ratelimit()) 
163 +               DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n", 
164 +                      NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex);
165 +       
166 +       return 0;
167 +}
168 +
169 +
170 +/* Stolen from ip_finish_output2
171 + * PRE : skb->dev is set to the device we are leaving by
172 + *       skb->dst is not NULL
173 + * POST: the packet is sent with the link layer header pushed
174 + *       the packet is destroyed
175 + */
176 +static void ip_direct_send(struct sk_buff *skb)
177 +{
178 +       struct dst_entry *dst = skb->dst;
179 +       struct hh_cache *hh = dst->hh;
180 +       struct net_device *dev = dst->dev;
181 +       int hh_len = LL_RESERVED_SPACE(dev);
182 +
183 +       /* Be paranoid, rather than too clever. */
184 +       if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
185 +               struct sk_buff *skb2;
186 +
187 +               skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
188 +               if (skb2 == NULL) {
189 +                       kfree_skb(skb);
190 +                       return;
191 +               }
192 +               if (skb->sk)
193 +                       skb_set_owner_w(skb2, skb->sk);
194 +               kfree_skb(skb);
195 +               skb = skb2;
196 +       }
197 +
198 +       if (hh) {
199 +               int hh_alen;
200 +
201 +               read_lock_bh(&hh->hh_lock);
202 +               hh_alen = HH_DATA_ALIGN(hh->hh_len);
203 +               memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
204 +               read_unlock_bh(&hh->hh_lock);
205 +               skb_push(skb, hh->hh_len);
206 +               hh->hh_output(skb);
207 +       } else if (dst->neighbour)
208 +               dst->neighbour->output(skb);
209 +       else {
210 +               if (net_ratelimit())
211 +                       DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n");
212 +               kfree_skb(skb);
213 +       }
214 +}
215 +
216 +
217 +/* PRE : skb->dev is set to the device we are leaving by
218 + * POST: - the packet is directly sent to the skb->dev device, without 
219 + *         pushing the link layer header.
220 + *       - the packet is destroyed
221 + */
222 +static inline int dev_direct_send(struct sk_buff *skb)
223 +{
224 +       return dev_queue_xmit(skb);
225 +}
226 +
227 +
228 +static unsigned int route_oif(const struct ipt_route_target_info *route_info,
229 +                             struct sk_buff *skb) 
230 +{
231 +       unsigned int ifindex = 0;
232 +       struct net_device *dev_out = NULL;
233 +
234 +       /* The user set the interface name to use.
235 +        * Getting the current interface index.
236 +        */
237 +       if ((dev_out = dev_get_by_name(route_info->oif))) {
238 +               ifindex = dev_out->ifindex;
239 +       } else {
240 +               /* Unknown interface name : packet dropped */
241 +               if (net_ratelimit()) 
242 +                       DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif);
243 +               return NF_DROP;
244 +       }
245 +
246 +       /* Trying the standard way of routing packets */
247 +       switch (route(skb, ifindex, route_info)) {
248 +       case 1:
249 +               dev_put(dev_out);
250 +               if (route_info->flags & IPT_ROUTE_CONTINUE)
251 +                       return IPT_CONTINUE;
252 +
253 +               ip_direct_send(skb);
254 +               return NF_STOLEN;
255 +
256 +       case 0:
257 +               /* Failed to send to oif. Trying the hard way */
258 +               if (route_info->flags & IPT_ROUTE_CONTINUE)
259 +                       return NF_DROP;
260 +
261 +               if (net_ratelimit()) 
262 +                       DEBUGP("ipt_ROUTE: forcing the use of %i\n",
263 +                              ifindex);
264 +
265 +               /* We have to force the use of an interface.
266 +                * This interface must be a tunnel interface since
267 +                * otherwise we can't guess the hw address for
268 +                * the packet. For a tunnel interface, no hw address
269 +                * is needed.
270 +                */
271 +               if ((dev_out->type != ARPHRD_TUNNEL)
272 +                   && (dev_out->type != ARPHRD_IPGRE)) {
273 +                       if (net_ratelimit()) 
274 +                               DEBUGP("ipt_ROUTE: can't guess the hw addr !\n");
275 +                       dev_put(dev_out);
276 +                       return NF_DROP;
277 +               }
278 +       
279 +               /* Send the packet. This will also free skb
280 +                * Do not go through the POST_ROUTING hook because 
281 +                * skb->dst is not set and because it will probably
282 +                * get confused by the destination IP address.
283 +                */
284 +               skb->dev = dev_out;
285 +               dev_direct_send(skb);
286 +               dev_put(dev_out);
287 +               return NF_STOLEN;
288 +               
289 +       default:
290 +               /* Unexpected error */
291 +               dev_put(dev_out);
292 +               return NF_DROP;
293 +       }
294 +}
295 +
296 +
297 +static unsigned int route_iif(const struct ipt_route_target_info *route_info,
298 +                             struct sk_buff *skb) 
299 +{
300 +       struct net_device *dev_in = NULL;
301 +
302 +       /* Getting the current interface index. */
303 +       if (!(dev_in = dev_get_by_name(route_info->iif))) {
304 +               if (net_ratelimit()) 
305 +                       DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->iif);
306 +               return NF_DROP;
307 +       }
308 +
309 +       skb->dev = dev_in;
310 +       dst_release(skb->dst);
311 +       skb->dst = NULL;
312 +
313 +       netif_rx(skb);
314 +       dev_put(dev_in);
315 +       return NF_STOLEN;
316 +}
317 +
318 +
319 +static unsigned int route_gw(const struct ipt_route_target_info *route_info,
320 +                            struct sk_buff *skb) 
321 +{
322 +       if (route(skb, 0, route_info)!=1)
323 +               return NF_DROP;
324 +
325 +       if (route_info->flags & IPT_ROUTE_CONTINUE)
326 +               return IPT_CONTINUE;
327 +
328 +       ip_direct_send(skb);
329 +       return NF_STOLEN;
330 +}
331 +
332 +
333 +/* To detect and deter routed packet loopback when using the --tee option,
334 + * we take a page out of the raw.patch book: on the copied skb, we set up
335 + * a fake ->nfct entry, pointing to the local &route_tee_track. We skip
336 + * routing packets when we see they already have that ->nfct.
337 + */
338 +
339 +static struct ip_conntrack route_tee_track;
340 +
341 +static unsigned int ipt_route_target(struct sk_buff **pskb,
342 +                                    const struct net_device *in,
343 +                                    const struct net_device *out,
344 +                                    unsigned int hooknum,
345 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
346 +                                    const struct xt_target *target,
347 +#endif
348 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
349 +                                    const void *targinfo,
350 +                                    void *userinfo)
351 +#else
352 +                                    const void *targinfo)
353 +#endif
354 +{
355 +       const struct ipt_route_target_info *route_info = targinfo;
356 +       struct sk_buff *skb = *pskb;
357 +       unsigned int res;
358 +
359 +       if (skb->nfct == &route_tee_track.ct_general) {
360 +               /* Loopback - a packet we already routed, is to be
361 +                * routed another time. Avoid that, now.
362 +                */
363 +               if (net_ratelimit()) 
364 +                       DEBUGP(KERN_DEBUG "ipt_ROUTE: loopback - DROP!\n");
365 +               return NF_DROP;
366 +       }
367 +
368 +       /* If we are at PREROUTING or INPUT hook
369 +        * the TTL isn't decreased by the IP stack
370 +        */
371 +       if (hooknum == NF_IP_PRE_ROUTING ||
372 +           hooknum == NF_IP_LOCAL_IN) {
373 +
374 +               struct iphdr *iph = skb->nh.iph;
375 +
376 +               if (iph->ttl <= 1) {
377 +                       struct rtable *rt;
378 +                       struct flowi fl = {
379 +                               .oif = 0,
380 +                               .nl_u = {
381 +                                       .ip4_u = {
382 +                                               .daddr = iph->daddr,
383 +                                               .saddr = iph->saddr,
384 +                                               .tos = RT_TOS(iph->tos),
385 +                                               .scope = ((iph->tos & RTO_ONLINK) ?
386 +                                                         RT_SCOPE_LINK :
387 +                                                         RT_SCOPE_UNIVERSE)
388 +                                       }
389 +                               } 
390 +                       };
391 +
392 +                       if (ip_route_output_key(&rt, &fl)) {
393 +                               return NF_DROP;
394 +                       }
395 +
396 +                       if (skb->dev == rt->u.dst.dev) {
397 +                               /* Drop old route. */
398 +                               dst_release(skb->dst);
399 +                               skb->dst = &rt->u.dst;
400 +
401 +                               /* this will traverse normal stack, and 
402 +                                * thus call conntrack on the icmp packet */
403 +                               icmp_send(skb, ICMP_TIME_EXCEEDED, 
404 +                                         ICMP_EXC_TTL, 0);
405 +                       }
406 +
407 +                       return NF_DROP;
408 +               }
409 +
410 +               /*
411 +                * If we are at INPUT the checksum must be recalculated since
412 +                * the length could change as the result of a defragmentation.
413 +                */
414 +               if(hooknum == NF_IP_LOCAL_IN) {
415 +                       iph->ttl = iph->ttl - 1;
416 +                       iph->check = 0;
417 +                       iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
418 +               } else {
419 +                       ip_decrease_ttl(iph);
420 +               }
421 +       }
422 +
423 +       if ((route_info->flags & IPT_ROUTE_TEE)) {
424 +               /*
425 +                * Copy the *pskb, and route the copy. Will later return
426 +                * IPT_CONTINUE for the original skb, which should continue
427 +                * on its way as if nothing happened. The copy should be
428 +                * independantly delivered to the ROUTE --gw.
429 +                */
430 +               skb = skb_copy(*pskb, GFP_ATOMIC);
431 +               if (!skb) {
432 +                       if (net_ratelimit()) 
433 +                               DEBUGP(KERN_DEBUG "ipt_ROUTE: copy failed!\n");
434 +                       return IPT_CONTINUE;
435 +               }
436 +       }
437 +
438 +       /* Tell conntrack to forget this packet since it may get confused 
439 +        * when a packet is leaving with dst address == our address.
440 +        * Good idea ? Dunno. Need advice.
441 +        *
442 +        * NEW: mark the skb with our &route_tee_track, so we avoid looping
443 +        * on any already routed packet.
444 +        */
445 +       if (!(route_info->flags & IPT_ROUTE_CONTINUE)) {
446 +               nf_conntrack_put(skb->nfct);
447 +               skb->nfct = &route_tee_track.ct_general;
448 +               skb->nfctinfo = IP_CT_NEW;
449 +               nf_conntrack_get(skb->nfct);
450 +       }
451 +
452 +       if (route_info->oif[0] != '\0') {
453 +               res = route_oif(route_info, skb);
454 +       } else if (route_info->iif[0] != '\0') {
455 +               res = route_iif(route_info, skb);
456 +       } else if (route_info->gw) {
457 +               res = route_gw(route_info, skb);
458 +       } else {
459 +               if (net_ratelimit()) 
460 +                       DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
461 +               res = IPT_CONTINUE;
462 +       }
463 +
464 +       if ((route_info->flags & IPT_ROUTE_TEE))
465 +               res = IPT_CONTINUE;
466 +
467 +       return res;
468 +}
469 +
470 +
471 +static int ipt_route_checkentry(const char *tablename,
472 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
473 +                               const void *e,
474 +#else
475 +                               const struct ipt_ip *ip,
476 +#endif
477 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
478 +                               const struct xt_target *target,
479 +#endif
480 +                               void *targinfo,
481 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
482 +                               unsigned int targinfosize,
483 +#endif
484 +                               unsigned int hook_mask)
485 +{
486 +       if (strcmp(tablename, "mangle") != 0) {
487 +               printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n",
488 +                      tablename);
489 +               return 0;
490 +       }
491 +
492 +       if (hook_mask & ~(  (1 << NF_IP_PRE_ROUTING)
493 +                           | (1 << NF_IP_LOCAL_IN)
494 +                           | (1 << NF_IP_FORWARD)
495 +                           | (1 << NF_IP_LOCAL_OUT)
496 +                           | (1 << NF_IP_POST_ROUTING))) {
497 +               printk("ipt_ROUTE: bad hook\n");
498 +               return 0;
499 +       }
500 +
501 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
502 +       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) {
503 +               printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n",
504 +                      targinfosize,
505 +                      IPT_ALIGN(sizeof(struct ipt_route_target_info)));
506 +               return 0;
507 +       }
508 +#endif
509 +
510 +       return 1;
511 +}
512 +
513 +
514 +static struct ipt_target ipt_route_reg = { 
515 +       .name = "ROUTE",
516 +       .target = ipt_route_target,
517 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
518 +       .targetsize = sizeof(struct ipt_route_target_info),
519 +#endif
520 +       .checkentry = ipt_route_checkentry,
521 +       .me = THIS_MODULE,
522 +};
523 +
524 +static int __init init(void)
525 +{
526 +       /* Set up fake conntrack (stolen from raw.patch):
527 +           - to never be deleted, not in any hashes */
528 +       atomic_set(&route_tee_track.ct_general.use, 1);
529 +       /*  - and look it like as a confirmed connection */
530 +       set_bit(IPS_CONFIRMED_BIT, &route_tee_track.status);
531 +       /* Initialize fake conntrack so that NAT will skip it */
532 +       route_tee_track.status |= IPS_NAT_DONE_MASK;
533 +
534 +       return xt_register_target(&ipt_route_reg);
535 +}
536 +
537 +
538 +static void __exit fini(void)
539 +{
540 +       xt_unregister_target(&ipt_route_reg);
541 +}
542 +
543 +module_init(init);
544 +module_exit(fini);
545 Index: linux-2.6.21.7/net/ipv4/netfilter/Kconfig
546 ===================================================================
547 --- linux-2.6.21.7.orig/net/ipv4/netfilter/Kconfig
548 +++ linux-2.6.21.7/net/ipv4/netfilter/Kconfig
549 @@ -807,5 +807,22 @@ config IP_NF_TARGET_SET
550           To compile it as a module, choose M here.  If unsure, say N.
551  
552  
553 +config IP_NF_TARGET_ROUTE
554 +       tristate  'ROUTE target support'
555 +       depends on IP_NF_MANGLE
556 +       help
557 +         This option adds a `ROUTE' target, which enables you to setup unusual
558 +         routes. For example, the ROUTE lets you route a received packet through 
559 +         an interface or towards a host, even if the regular destination of the 
560 +         packet is the router itself. The ROUTE target is also able to change the 
561 +         incoming interface of a packet.
562 +       
563 +         The target can be or not a final target. It has to be used inside the 
564 +         mangle table.
565 +         
566 +         If you want to compile it as a module, say M here and read
567 +         Documentation/modules.txt.  The module will be called ipt_ROUTE.o.
568 +         If unsure, say `N'.
569 +
570  endmenu
571  
572 Index: linux-2.6.21.7/net/ipv4/netfilter/Makefile
573 ===================================================================
574 --- linux-2.6.21.7.orig/net/ipv4/netfilter/Makefile
575 +++ linux-2.6.21.7/net/ipv4/netfilter/Makefile
576 @@ -102,6 +102,7 @@ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_EC
577  obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o
578  obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
579  obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
580 +obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o
581  obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
582  obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
583  obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
584 Index: linux-2.6.21.7/net/ipv6/ipv6_syms.c
585 ===================================================================
586 --- linux-2.6.21.7.orig/net/ipv6/ipv6_syms.c
587 +++ linux-2.6.21.7/net/ipv6/ipv6_syms.c
588 @@ -10,6 +10,7 @@ EXPORT_SYMBOL(icmpv6_send);
589  EXPORT_SYMBOL(icmpv6_statistics);
590  EXPORT_SYMBOL(icmpv6_err_convert);
591  EXPORT_SYMBOL(ndisc_mc_map);
592 +EXPORT_SYMBOL(nd_tbl);
593  EXPORT_SYMBOL(register_inet6addr_notifier);
594  EXPORT_SYMBOL(unregister_inet6addr_notifier);
595  EXPORT_SYMBOL(ip6_route_output);
596 Index: linux-2.6.21.7/net/ipv6/netfilter/ip6t_ROUTE.c
597 ===================================================================
598 --- /dev/null
599 +++ linux-2.6.21.7/net/ipv6/netfilter/ip6t_ROUTE.c
600 @@ -0,0 +1,330 @@
601 +/*
602 + * This implements the ROUTE v6 target, which enables you to setup unusual
603 + * routes not supported by the standard kernel routing table.
604 + *
605 + * Copyright (C) 2003 Cedric de Launois <delaunois@info.ucl.ac.be>
606 + *
607 + * v 1.1 2004/11/23
608 + *
609 + * This software is distributed under GNU GPL v2, 1991
610 + */
611 +
612 +#include <linux/module.h>
613 +#include <linux/skbuff.h>
614 +#include <linux/ipv6.h>
615 +#include <linux/netfilter_ipv6/ip6_tables.h>
616 +#include <linux/netfilter_ipv6/ip6t_ROUTE.h>
617 +#include <linux/netdevice.h>
618 +#include <linux/version.h>
619 +#include <net/ipv6.h>
620 +#include <net/ndisc.h>
621 +#include <net/ip6_route.h>
622 +#include <linux/icmpv6.h>
623 +
624 +#if 1
625 +#define DEBUGP printk
626 +#else
627 +#define DEBUGP(format, args...)
628 +#endif
629 +
630 +#define NIP6(addr) \
631 +       ntohs((addr).s6_addr16[0]), \
632 +       ntohs((addr).s6_addr16[1]), \
633 +       ntohs((addr).s6_addr16[2]), \
634 +       ntohs((addr).s6_addr16[3]), \
635 +       ntohs((addr).s6_addr16[4]), \
636 +       ntohs((addr).s6_addr16[5]), \
637 +       ntohs((addr).s6_addr16[6]), \
638 +       ntohs((addr).s6_addr16[7])
639 +
640 +/* Route the packet according to the routing keys specified in
641 + * route_info. Keys are :
642 + *  - ifindex : 
643 + *      0 if no oif preferred, 
644 + *      otherwise set to the index of the desired oif
645 + *  - route_info->gw :
646 + *      0 if no gateway specified,
647 + *      otherwise set to the next host to which the pkt must be routed
648 + * If success, skb->dev is the output device to which the packet must 
649 + * be sent and skb->dst is not NULL
650 + *
651 + * RETURN:  1 if the packet was succesfully routed to the 
652 + *            destination desired
653 + *          0 if the kernel routing table could not route the packet
654 + *            according to the keys specified
655 + */
656 +static int 
657 +route6(struct sk_buff *skb,
658 +       unsigned int ifindex,
659 +       const struct ip6t_route_target_info *route_info)
660 +{
661 +       struct rt6_info *rt = NULL;
662 +       struct ipv6hdr *ipv6h = skb->nh.ipv6h;
663 +       struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
664 +
665 +       DEBUGP("ip6t_ROUTE: called with: ");
666 +       DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
667 +       DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
668 +       DEBUGP("OUT=%s\n", route_info->oif);
669 +       
670 +       if (ipv6_addr_any(gw))
671 +               rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
672 +       else
673 +               rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
674 +
675 +       if (!rt)
676 +               goto no_route;
677 +
678 +       DEBUGP("ip6t_ROUTE: routing gives: ");
679 +       DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
680 +       DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
681 +       DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
682 +
683 +       if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
684 +               goto wrong_route;
685 +       
686 +       if (!rt->rt6i_nexthop) {
687 +               DEBUGP("ip6t_ROUTE: discovering neighbour\n");
688 +               rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
689 +       }
690 +
691 +       /* Drop old route. */
692 +       dst_release(skb->dst);
693 +       skb->dst = &rt->u.dst;
694 +       skb->dev = rt->rt6i_dev;
695 +       return 1;
696 +
697 + wrong_route:
698 +       dst_release(&rt->u.dst);
699 + no_route:
700 +       if (!net_ratelimit())
701 +               return 0;
702 +
703 +       printk("ip6t_ROUTE: no explicit route found ");
704 +       if (ifindex)
705 +               printk("via interface %s ", route_info->oif);
706 +       if (!ipv6_addr_any(gw))
707 +               printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
708 +       printk("\n");
709 +       return 0;
710 +}
711 +
712 +
713 +/* Stolen from ip6_output_finish
714 + * PRE : skb->dev is set to the device we are leaving by
715 + *       skb->dst is not NULL
716 + * POST: the packet is sent with the link layer header pushed
717 + *       the packet is destroyed
718 + */
719 +static void ip_direct_send(struct sk_buff *skb)
720 +{
721 +       struct dst_entry *dst = skb->dst;
722 +       struct hh_cache *hh = dst->hh;
723 +
724 +       if (hh) {
725 +               read_lock_bh(&hh->hh_lock);
726 +               memcpy(skb->data - 16, hh->hh_data, 16);
727 +               read_unlock_bh(&hh->hh_lock);
728 +               skb_push(skb, hh->hh_len);
729 +               hh->hh_output(skb);
730 +       } else if (dst->neighbour)
731 +               dst->neighbour->output(skb);
732 +       else {
733 +               if (net_ratelimit())
734 +                       DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n");
735 +               kfree_skb(skb);
736 +       }
737 +}
738 +
739 +
740 +static unsigned int 
741 +route6_oif(const struct ip6t_route_target_info *route_info,
742 +          struct sk_buff *skb) 
743 +{
744 +       unsigned int ifindex = 0;
745 +       struct net_device *dev_out = NULL;
746 +
747 +       /* The user set the interface name to use.
748 +        * Getting the current interface index.
749 +        */
750 +       if ((dev_out = dev_get_by_name(route_info->oif))) {
751 +               ifindex = dev_out->ifindex;
752 +       } else {
753 +               /* Unknown interface name : packet dropped */
754 +               if (net_ratelimit()) 
755 +                       DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
756 +
757 +               if (route_info->flags & IP6T_ROUTE_CONTINUE)
758 +                       return IP6T_CONTINUE;
759 +               else
760 +                       return NF_DROP;
761 +       }
762 +
763 +       /* Trying the standard way of routing packets */
764 +       if (route6(skb, ifindex, route_info)) {
765 +               dev_put(dev_out);
766 +               if (route_info->flags & IP6T_ROUTE_CONTINUE)
767 +                       return IP6T_CONTINUE;
768 +               
769 +               ip_direct_send(skb);
770 +               return NF_STOLEN;
771 +       } else 
772 +               return NF_DROP;
773 +}
774 +
775 +
776 +static unsigned int 
777 +route6_gw(const struct ip6t_route_target_info *route_info,
778 +         struct sk_buff *skb) 
779 +{
780 +       if (route6(skb, 0, route_info)) {
781 +               if (route_info->flags & IP6T_ROUTE_CONTINUE)
782 +                       return IP6T_CONTINUE;
783 +
784 +               ip_direct_send(skb);
785 +               return NF_STOLEN;
786 +       } else
787 +               return NF_DROP;
788 +}
789 +
790 +
791 +static unsigned int 
792 +ip6t_route_target(struct sk_buff **pskb,
793 +                 const struct net_device *in,
794 +                 const struct net_device *out,
795 +                 unsigned int hooknum,
796 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
797 +                 const struct xt_target *target,
798 +#endif
799 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
800 +                 const void *targinfo,
801 +                 void *userinfo)
802 +#else
803 +                 const void *targinfo)
804 +#endif
805 +{
806 +       const struct ip6t_route_target_info *route_info = targinfo;
807 +       struct sk_buff *skb = *pskb;
808 +       struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
809 +       unsigned int res;
810 +
811 +       if (route_info->flags & IP6T_ROUTE_CONTINUE)
812 +               goto do_it;
813 +
814 +       /* If we are at PREROUTING or INPUT hook
815 +        * the TTL isn't decreased by the IP stack
816 +        */
817 +       if (hooknum == NF_IP6_PRE_ROUTING ||
818 +           hooknum == NF_IP6_LOCAL_IN) {
819 +
820 +               struct ipv6hdr *ipv6h = skb->nh.ipv6h;
821 +
822 +               if (ipv6h->hop_limit <= 1) {
823 +                       /* Force OUTPUT device used as source address */
824 +                       skb->dev = skb->dst->dev;
825 +
826 +                       icmpv6_send(skb, ICMPV6_TIME_EXCEED, 
827 +                                   ICMPV6_EXC_HOPLIMIT, 0, skb->dev);
828 +
829 +                       return NF_DROP;
830 +               }
831 +
832 +               ipv6h->hop_limit--;
833 +       }
834 +
835 +       if ((route_info->flags & IP6T_ROUTE_TEE)) {
836 +               /*
837 +                * Copy the *pskb, and route the copy. Will later return
838 +                * IP6T_CONTINUE for the original skb, which should continue
839 +                * on its way as if nothing happened. The copy should be
840 +                * independantly delivered to the ROUTE --gw.
841 +                */
842 +               skb = skb_copy(*pskb, GFP_ATOMIC);
843 +               if (!skb) {
844 +                       if (net_ratelimit()) 
845 +                               DEBUGP(KERN_DEBUG "ip6t_ROUTE: copy failed!\n");
846 +                       return IP6T_CONTINUE;
847 +               }
848 +       }
849 +
850 +do_it:
851 +       if (route_info->oif[0]) {
852 +               res = route6_oif(route_info, skb);
853 +       } else if (!ipv6_addr_any(gw)) {
854 +               res = route6_gw(route_info, skb);
855 +       } else {
856 +               if (net_ratelimit()) 
857 +                       DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
858 +               res = IP6T_CONTINUE;
859 +       }
860 +
861 +       if ((route_info->flags & IP6T_ROUTE_TEE))
862 +               res = IP6T_CONTINUE;
863 +
864 +       return res;
865 +}
866 +
867 +
868 +static int 
869 +ip6t_route_checkentry(const char *tablename,
870 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
871 +                     const void *entry,
872 +#else
873 +                     const struct ip6t_entry *entry
874 +#endif
875 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
876 +                     const struct xt_target *target,
877 +#endif
878 +                     void *targinfo,
879 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
880 +                     unsigned int targinfosize,
881 +#endif
882 +                     unsigned int hook_mask)
883 +{
884 +       if (strcmp(tablename, "mangle") != 0) {
885 +               printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
886 +               return 0;
887 +       }
888 +
889 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
890 +       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) {
891 +               printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n",
892 +                      targinfosize,
893 +                      IP6T_ALIGN(sizeof(struct ip6t_route_target_info)));
894 +               return 0;
895 +       }
896 +#endif
897 +
898 +       return 1;
899 +}
900 +
901 +
902 +static struct ip6t_target ip6t_route_reg = {
903 +       .name       = "ROUTE",
904 +       .target     = ip6t_route_target,
905 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
906 +       .targetsize = sizeof(struct ip6t_route_target_info),
907 +#endif
908 +       .checkentry = ip6t_route_checkentry,
909 +       .me         = THIS_MODULE
910 +};
911 +
912 +
913 +static int __init init(void)
914 +{
915 +       printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
916 +       if (xt_register_target(&ip6t_route_reg))
917 +               return -EINVAL;
918 +
919 +       return 0;
920 +}
921 +
922 +
923 +static void __exit fini(void)
924 +{
925 +       xt_unregister_target(&ip6t_route_reg);
926 +}
927 +
928 +module_init(init);
929 +module_exit(fini);
930 +MODULE_LICENSE("GPL");
931 Index: linux-2.6.21.7/net/ipv6/netfilter/Kconfig
932 ===================================================================
933 --- linux-2.6.21.7.orig/net/ipv6/netfilter/Kconfig
934 +++ linux-2.6.21.7/net/ipv6/netfilter/Kconfig
935 @@ -209,5 +209,18 @@ config IP6_NF_RAW
936           If you want to compile it as a module, say M here and read
937           <file:Documentation/modules.txt>.  If unsure, say `N'.
938  
939 +config IP6_NF_TARGET_ROUTE
940 +       tristate 'ROUTE target support'
941 +       depends on IP6_NF_MANGLE
942 +       help
943 +         This option adds a `ROUTE' target, which enables you to setup unusual
944 +         routes. The ROUTE target is also able to change the incoming interface
945 +         of a packet.
946 +       
947 +         The target can be or not a final target. It has to be used inside the 
948 +         mangle table.
949 +         
950 +         Not working as a module.
951 +
952  endmenu
953  
954 Index: linux-2.6.21.7/net/ipv6/netfilter/Makefile
955 ===================================================================
956 --- linux-2.6.21.7.orig/net/ipv6/netfilter/Makefile
957 +++ linux-2.6.21.7/net/ipv6/netfilter/Makefile
958 @@ -20,6 +20,7 @@ obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_
959  obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
960  obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
961  obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
962 +obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o
963  obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
964  
965  # objects for l3 independent conntrack