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