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