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