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