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