7e8491c3e3b2673e5c6f910d53e0b9c11f65e594
[openwrt/svn-archive/archive.git] / target / linux / generic-2.6 / patches / 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