refresh generic 2.6.22 patches
[openwrt/staging/florian.git] / target / linux / generic-2.6 / patches-2.6.22 / 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 <net/netfilter/nf_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 = ip_hdr(skb);
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 nf_conn 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 = ip_hdr(skb);
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 @@ -552,5 +552,22 @@
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 @@ -60,6 +60,7 @@
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_TARGET_LOG) += ipt_LOG.o
574 --- a/net/ipv6/ndisc.c
575 +++ b/net/ipv6/ndisc.c
576 @@ -154,6 +154,8 @@
577 .gc_thresh3 = 1024,
578 };
579
580 +EXPORT_SYMBOL(nd_tbl);
581 +
582 /* ND options */
583 struct ndisc_options {
584 struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];
585 --- /dev/null
586 +++ b/net/ipv6/netfilter/ip6t_ROUTE.c
587 @@ -0,0 +1,330 @@
588 +/*
589 + * This implements the ROUTE v6 target, which enables you to setup unusual
590 + * routes not supported by the standard kernel routing table.
591 + *
592 + * Copyright (C) 2003 Cedric de Launois <delaunois@info.ucl.ac.be>
593 + *
594 + * v 1.1 2004/11/23
595 + *
596 + * This software is distributed under GNU GPL v2, 1991
597 + */
598 +
599 +#include <linux/module.h>
600 +#include <linux/skbuff.h>
601 +#include <linux/ipv6.h>
602 +#include <linux/netfilter_ipv6/ip6_tables.h>
603 +#include <linux/netfilter_ipv6/ip6t_ROUTE.h>
604 +#include <linux/netdevice.h>
605 +#include <linux/version.h>
606 +#include <net/ipv6.h>
607 +#include <net/ndisc.h>
608 +#include <net/ip6_route.h>
609 +#include <linux/icmpv6.h>
610 +
611 +#if 1
612 +#define DEBUGP printk
613 +#else
614 +#define DEBUGP(format, args...)
615 +#endif
616 +
617 +#define NIP6(addr) \
618 + ntohs((addr).s6_addr16[0]), \
619 + ntohs((addr).s6_addr16[1]), \
620 + ntohs((addr).s6_addr16[2]), \
621 + ntohs((addr).s6_addr16[3]), \
622 + ntohs((addr).s6_addr16[4]), \
623 + ntohs((addr).s6_addr16[5]), \
624 + ntohs((addr).s6_addr16[6]), \
625 + ntohs((addr).s6_addr16[7])
626 +
627 +/* Route the packet according to the routing keys specified in
628 + * route_info. Keys are :
629 + * - ifindex :
630 + * 0 if no oif preferred,
631 + * otherwise set to the index of the desired oif
632 + * - route_info->gw :
633 + * 0 if no gateway specified,
634 + * otherwise set to the next host to which the pkt must be routed
635 + * If success, skb->dev is the output device to which the packet must
636 + * be sent and skb->dst is not NULL
637 + *
638 + * RETURN: 1 if the packet was succesfully routed to the
639 + * destination desired
640 + * 0 if the kernel routing table could not route the packet
641 + * according to the keys specified
642 + */
643 +static int
644 +route6(struct sk_buff *skb,
645 + unsigned int ifindex,
646 + const struct ip6t_route_target_info *route_info)
647 +{
648 + struct rt6_info *rt = NULL;
649 + struct ipv6hdr *ipv6h = ipv6_hdr(skb);
650 + struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
651 +
652 + DEBUGP("ip6t_ROUTE: called with: ");
653 + DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
654 + DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
655 + DEBUGP("OUT=%s\n", route_info->oif);
656 +
657 + if (ipv6_addr_any(gw))
658 + rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
659 + else
660 + rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
661 +
662 + if (!rt)
663 + goto no_route;
664 +
665 + DEBUGP("ip6t_ROUTE: routing gives: ");
666 + DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
667 + DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
668 + DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
669 +
670 + if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
671 + goto wrong_route;
672 +
673 + if (!rt->rt6i_nexthop) {
674 + DEBUGP("ip6t_ROUTE: discovering neighbour\n");
675 + rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
676 + }
677 +
678 + /* Drop old route. */
679 + dst_release(skb->dst);
680 + skb->dst = &rt->u.dst;
681 + skb->dev = rt->rt6i_dev;
682 + return 1;
683 +
684 + wrong_route:
685 + dst_release(&rt->u.dst);
686 + no_route:
687 + if (!net_ratelimit())
688 + return 0;
689 +
690 + printk("ip6t_ROUTE: no explicit route found ");
691 + if (ifindex)
692 + printk("via interface %s ", route_info->oif);
693 + if (!ipv6_addr_any(gw))
694 + printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
695 + printk("\n");
696 + return 0;
697 +}
698 +
699 +
700 +/* Stolen from ip6_output_finish
701 + * PRE : skb->dev is set to the device we are leaving by
702 + * skb->dst is not NULL
703 + * POST: the packet is sent with the link layer header pushed
704 + * the packet is destroyed
705 + */
706 +static void ip_direct_send(struct sk_buff *skb)
707 +{
708 + struct dst_entry *dst = skb->dst;
709 + struct hh_cache *hh = dst->hh;
710 +
711 + if (hh) {
712 + read_lock_bh(&hh->hh_lock);
713 + memcpy(skb->data - 16, hh->hh_data, 16);
714 + read_unlock_bh(&hh->hh_lock);
715 + skb_push(skb, hh->hh_len);
716 + hh->hh_output(skb);
717 + } else if (dst->neighbour)
718 + dst->neighbour->output(skb);
719 + else {
720 + if (net_ratelimit())
721 + DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n");
722 + kfree_skb(skb);
723 + }
724 +}
725 +
726 +
727 +static unsigned int
728 +route6_oif(const struct ip6t_route_target_info *route_info,
729 + struct sk_buff *skb)
730 +{
731 + unsigned int ifindex = 0;
732 + struct net_device *dev_out = NULL;
733 +
734 + /* The user set the interface name to use.
735 + * Getting the current interface index.
736 + */
737 + if ((dev_out = dev_get_by_name(route_info->oif))) {
738 + ifindex = dev_out->ifindex;
739 + } else {
740 + /* Unknown interface name : packet dropped */
741 + if (net_ratelimit())
742 + DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
743 +
744 + if (route_info->flags & IP6T_ROUTE_CONTINUE)
745 + return IP6T_CONTINUE;
746 + else
747 + return NF_DROP;
748 + }
749 +
750 + /* Trying the standard way of routing packets */
751 + if (route6(skb, ifindex, route_info)) {
752 + dev_put(dev_out);
753 + if (route_info->flags & IP6T_ROUTE_CONTINUE)
754 + return IP6T_CONTINUE;
755 +
756 + ip_direct_send(skb);
757 + return NF_STOLEN;
758 + } else
759 + return NF_DROP;
760 +}
761 +
762 +
763 +static unsigned int
764 +route6_gw(const struct ip6t_route_target_info *route_info,
765 + struct sk_buff *skb)
766 +{
767 + if (route6(skb, 0, route_info)) {
768 + if (route_info->flags & IP6T_ROUTE_CONTINUE)
769 + return IP6T_CONTINUE;
770 +
771 + ip_direct_send(skb);
772 + return NF_STOLEN;
773 + } else
774 + return NF_DROP;
775 +}
776 +
777 +
778 +static unsigned int
779 +ip6t_route_target(struct sk_buff **pskb,
780 + const struct net_device *in,
781 + const struct net_device *out,
782 + unsigned int hooknum,
783 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
784 + const struct xt_target *target,
785 +#endif
786 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
787 + const void *targinfo,
788 + void *userinfo)
789 +#else
790 + const void *targinfo)
791 +#endif
792 +{
793 + const struct ip6t_route_target_info *route_info = targinfo;
794 + struct sk_buff *skb = *pskb;
795 + struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
796 + unsigned int res;
797 +
798 + if (route_info->flags & IP6T_ROUTE_CONTINUE)
799 + goto do_it;
800 +
801 + /* If we are at PREROUTING or INPUT hook
802 + * the TTL isn't decreased by the IP stack
803 + */
804 + if (hooknum == NF_IP6_PRE_ROUTING ||
805 + hooknum == NF_IP6_LOCAL_IN) {
806 +
807 + struct ipv6hdr *ipv6h = ipv6_hdr(skb);
808 +
809 + if (ipv6h->hop_limit <= 1) {
810 + /* Force OUTPUT device used as source address */
811 + skb->dev = skb->dst->dev;
812 +
813 + icmpv6_send(skb, ICMPV6_TIME_EXCEED,
814 + ICMPV6_EXC_HOPLIMIT, 0, skb->dev);
815 +
816 + return NF_DROP;
817 + }
818 +
819 + ipv6h->hop_limit--;
820 + }
821 +
822 + if ((route_info->flags & IP6T_ROUTE_TEE)) {
823 + /*
824 + * Copy the *pskb, and route the copy. Will later return
825 + * IP6T_CONTINUE for the original skb, which should continue
826 + * on its way as if nothing happened. The copy should be
827 + * independantly delivered to the ROUTE --gw.
828 + */
829 + skb = skb_copy(*pskb, GFP_ATOMIC);
830 + if (!skb) {
831 + if (net_ratelimit())
832 + DEBUGP(KERN_DEBUG "ip6t_ROUTE: copy failed!\n");
833 + return IP6T_CONTINUE;
834 + }
835 + }
836 +
837 +do_it:
838 + if (route_info->oif[0]) {
839 + res = route6_oif(route_info, skb);
840 + } else if (!ipv6_addr_any(gw)) {
841 + res = route6_gw(route_info, skb);
842 + } else {
843 + if (net_ratelimit())
844 + DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
845 + res = IP6T_CONTINUE;
846 + }
847 +
848 + if ((route_info->flags & IP6T_ROUTE_TEE))
849 + res = IP6T_CONTINUE;
850 +
851 + return res;
852 +}
853 +
854 +
855 +static int
856 +ip6t_route_checkentry(const char *tablename,
857 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
858 + const void *entry,
859 +#else
860 + const struct ip6t_entry *entry
861 +#endif
862 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
863 + const struct xt_target *target,
864 +#endif
865 + void *targinfo,
866 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
867 + unsigned int targinfosize,
868 +#endif
869 + unsigned int hook_mask)
870 +{
871 + if (strcmp(tablename, "mangle") != 0) {
872 + printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
873 + return 0;
874 + }
875 +
876 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
877 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) {
878 + printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n",
879 + targinfosize,
880 + IP6T_ALIGN(sizeof(struct ip6t_route_target_info)));
881 + return 0;
882 + }
883 +#endif
884 +
885 + return 1;
886 +}
887 +
888 +
889 +static struct ip6t_target ip6t_route_reg = {
890 + .name = "ROUTE",
891 + .target = ip6t_route_target,
892 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
893 + .targetsize = sizeof(struct ip6t_route_target_info),
894 +#endif
895 + .checkentry = ip6t_route_checkentry,
896 + .me = THIS_MODULE
897 +};
898 +
899 +
900 +static int __init init(void)
901 +{
902 + printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
903 + if (xt_register_target(&ip6t_route_reg))
904 + return -EINVAL;
905 +
906 + return 0;
907 +}
908 +
909 +
910 +static void __exit fini(void)
911 +{
912 + xt_unregister_target(&ip6t_route_reg);
913 +}
914 +
915 +module_init(init);
916 +module_exit(fini);
917 +MODULE_LICENSE("GPL");
918 --- a/net/ipv6/netfilter/Kconfig
919 +++ b/net/ipv6/netfilter/Kconfig
920 @@ -209,5 +209,18 @@
921 If you want to compile it as a module, say M here and read
922 <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
923
924 +config IP6_NF_TARGET_ROUTE
925 + tristate 'ROUTE target support'
926 + depends on IP6_NF_MANGLE
927 + help
928 + This option adds a `ROUTE' target, which enables you to setup unusual
929 + routes. The ROUTE target is also able to change the incoming interface
930 + of a packet.
931 +
932 + The target can be or not a final target. It has to be used inside the
933 + mangle table.
934 +
935 + Not working as a module.
936 +
937 endmenu
938
939 --- a/net/ipv6/netfilter/Makefile
940 +++ b/net/ipv6/netfilter/Makefile
941 @@ -20,6 +20,7 @@
942 obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
943 obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
944 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
945 +obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o
946 obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
947
948 # objects for l3 independent conntrack