]> git.pld-linux.org Git - packages/kernel.git/blob - pom-ng-ROUTE-20060504.patch
- sip conntrack
[packages/kernel.git] / pom-ng-ROUTE-20060504.patch
1  include/linux/netfilter_ipv4/ipt_ROUTE.h  |   23 +
2  include/linux/netfilter_ipv6/ip6t_ROUTE.h |   23 +
3  net/ipv4/netfilter/Kconfig                |   17 +
4  net/ipv4/netfilter/Makefile               |    1 
5  net/ipv4/netfilter/ipt_ROUTE.c            |  464 ++++++++++++++++++++++++++++++
6  net/ipv6/ipv6_syms.c                      |    1 
7  net/ipv6/netfilter/Kconfig                |   13 
8  net/ipv6/netfilter/Makefile               |    1 
9  net/ipv6/netfilter/ip6t_ROUTE.c           |  308 +++++++++++++++++++
10  9 files changed, 851 insertions(+)
11
12 diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv4/ipt_ROUTE.h linux/include/linux/netfilter_ipv4/ipt_ROUTE.h
13 --- linux.org/include/linux/netfilter_ipv4/ipt_ROUTE.h  1970-01-01 01:00:00.000000000 +0100
14 +++ linux/include/linux/netfilter_ipv4/ipt_ROUTE.h      2006-05-04 11:20:35.000000000 +0200
15 @@ -0,0 +1,23 @@
16 +/* Header file for iptables ipt_ROUTE target
17 + *
18 + * (C) 2002 by Cédric de Launois <delaunois@info.ucl.ac.be>
19 + *
20 + * This software is distributed under GNU GPL v2, 1991
21 + */
22 +#ifndef _IPT_ROUTE_H_target
23 +#define _IPT_ROUTE_H_target
24 +
25 +#define IPT_ROUTE_IFNAMSIZ 16
26 +
27 +struct ipt_route_target_info {
28 +       char      oif[IPT_ROUTE_IFNAMSIZ];      /* Output Interface Name */
29 +       char      iif[IPT_ROUTE_IFNAMSIZ];      /* Input Interface Name  */
30 +       u_int32_t gw;                           /* IP address of gateway */
31 +       u_int8_t  flags;
32 +};
33 +
34 +/* Values for "flags" field */
35 +#define IPT_ROUTE_CONTINUE        0x01
36 +#define IPT_ROUTE_TEE             0x02
37 +
38 +#endif /*_IPT_ROUTE_H_target*/
39 diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h
40 --- linux.org/include/linux/netfilter_ipv6/ip6t_ROUTE.h 1970-01-01 01:00:00.000000000 +0100
41 +++ linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h     2006-05-04 11:20:35.000000000 +0200
42 @@ -0,0 +1,23 @@
43 +/* Header file for iptables ip6t_ROUTE target
44 + *
45 + * (C) 2003 by Cédric de Launois <delaunois@info.ucl.ac.be>
46 + *
47 + * This software is distributed under GNU GPL v2, 1991
48 + */
49 +#ifndef _IPT_ROUTE_H_target
50 +#define _IPT_ROUTE_H_target
51 +
52 +#define IP6T_ROUTE_IFNAMSIZ 16
53 +
54 +struct ip6t_route_target_info {
55 +       char      oif[IP6T_ROUTE_IFNAMSIZ];     /* Output Interface Name */
56 +       char      iif[IP6T_ROUTE_IFNAMSIZ];     /* Input Interface Name  */
57 +       u_int32_t gw[4];                        /* IPv6 address of gateway */
58 +       u_int8_t  flags;
59 +};
60 +
61 +/* Values for "flags" field */
62 +#define IP6T_ROUTE_CONTINUE        0x01
63 +#define IP6T_ROUTE_TEE             0x02
64 +
65 +#endif /*_IP6T_ROUTE_H_target*/
66 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig
67 --- linux.org/net/ipv4/netfilter/Kconfig        2006-05-02 23:38:44.000000000 +0200
68 +++ linux/net/ipv4/netfilter/Kconfig    2006-05-04 11:20:35.000000000 +0200
69 @@ -606,5 +606,22 @@
70           Allows altering the ARP packet payload: source and destination
71           hardware and network addresses.
72  
73 +config IP_NF_TARGET_ROUTE
74 +       tristate  'ROUTE target support'
75 +       depends on IP_NF_MANGLE
76 +       help
77 +         This option adds a `ROUTE' target, which enables you to setup unusual
78 +         routes. For example, the ROUTE lets you route a received packet through 
79 +         an interface or towards a host, even if the regular destination of the 
80 +         packet is the router itself. The ROUTE target is also able to change the 
81 +         incoming interface of a packet.
82 +       
83 +         The target can be or not a final target. It has to be used inside the 
84 +         mangle table.
85 +         
86 +         If you want to compile it as a module, say M here and read
87 +         Documentation/modules.txt.  The module will be called ipt_ROUTE.o.
88 +         If unsure, say `N'.
89 +
90  endmenu
91  
92 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
93 --- linux.org/net/ipv4/netfilter/Makefile       2006-05-02 23:38:44.000000000 +0200
94 +++ linux/net/ipv4/netfilter/Makefile   2006-05-04 11:20:35.000000000 +0200
95 @@ -0,0 +0,1 @@
96 +obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o
97 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_ROUTE.c linux/net/ipv4/netfilter/ipt_ROUTE.c
98 --- linux.org/net/ipv4/netfilter/ipt_ROUTE.c    1970-01-01 01:00:00.000000000 +0100
99 +++ linux/net/ipv4/netfilter/ipt_ROUTE.c        2006-05-04 11:20:35.000000000 +0200
100 @@ -0,0 +1,464 @@
101 +/*
102 + * This implements the ROUTE target, which enables you to setup unusual
103 + * routes not supported by the standard kernel routing table.
104 + *
105 + * Copyright (C) 2002 Cedric de Launois <delaunois@info.ucl.ac.be>
106 + *
107 + * v 1.11 2004/11/23
108 + *
109 + * This software is distributed under GNU GPL v2, 1991
110 + */
111 +
112 +#include <linux/module.h>
113 +#include <linux/skbuff.h>
114 +#include <linux/ip.h>
115 +#include <linux/netfilter_ipv4/ip_tables.h>
116 +#include <linux/netfilter_ipv4/ip_conntrack.h>
117 +#include <linux/netfilter_ipv4/ipt_ROUTE.h>
118 +#include <linux/netdevice.h>
119 +#include <linux/route.h>
120 +#include <linux/if_arp.h>
121 +#include <net/ip.h>
122 +#include <net/route.h>
123 +#include <net/icmp.h>
124 +#include <net/checksum.h>
125 +
126 +#if 0
127 +#define DEBUGP printk
128 +#else
129 +#define DEBUGP(format, args...)
130 +#endif
131 +
132 +MODULE_LICENSE("GPL");
133 +MODULE_AUTHOR("Cedric de Launois <delaunois@info.ucl.ac.be>");
134 +MODULE_DESCRIPTION("iptables ROUTE target module");
135 +
136 +/* Try to route the packet according to the routing keys specified in
137 + * route_info. Keys are :
138 + *  - ifindex : 
139 + *      0 if no oif preferred, 
140 + *      otherwise set to the index of the desired oif
141 + *  - route_info->gw :
142 + *      0 if no gateway specified,
143 + *      otherwise set to the next host to which the pkt must be routed
144 + * If success, skb->dev is the output device to which the packet must 
145 + * be sent and skb->dst is not NULL
146 + *
147 + * RETURN: -1 if an error occured
148 + *          1 if the packet was succesfully routed to the 
149 + *            destination desired
150 + *          0 if the kernel routing table could not route the packet
151 + *            according to the keys specified
152 + */
153 +static int route(struct sk_buff *skb,
154 +                unsigned int ifindex,
155 +                const struct ipt_route_target_info *route_info)
156 +{
157 +       int err;
158 +       struct rtable *rt;
159 +       struct iphdr *iph = skb->nh.iph;
160 +       struct flowi fl = {
161 +               .oif = ifindex,
162 +               .nl_u = {
163 +                       .ip4_u = {
164 +                               .daddr = iph->daddr,
165 +                               .saddr = 0,
166 +                               .tos = RT_TOS(iph->tos),
167 +                               .scope = RT_SCOPE_UNIVERSE,
168 +                       }
169 +               } 
170 +       };
171 +       
172 +       /* The destination address may be overloaded by the target */
173 +       if (route_info->gw)
174 +               fl.fl4_dst = route_info->gw;
175 +       
176 +       /* Trying to route the packet using the standard routing table. */
177 +       if ((err = ip_route_output_key(&rt, &fl))) {
178 +               if (net_ratelimit()) 
179 +                       DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err);
180 +               return -1;
181 +       }
182 +       
183 +       /* Drop old route. */
184 +       dst_release(skb->dst);
185 +       skb->dst = NULL;
186 +
187 +       /* Success if no oif specified or if the oif correspond to the 
188 +        * one desired */
189 +       if (!ifindex || rt->u.dst.dev->ifindex == ifindex) {
190 +               skb->dst = &rt->u.dst;
191 +               skb->dev = skb->dst->dev;
192 +               skb->protocol = htons(ETH_P_IP);
193 +               return 1;
194 +       }
195 +       
196 +       /* The interface selected by the routing table is not the one
197 +        * specified by the user. This may happen because the dst address
198 +        * is one of our own addresses.
199 +        */
200 +       if (net_ratelimit()) 
201 +               DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n", 
202 +                      NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex);
203 +       
204 +       return 0;
205 +}
206 +
207 +
208 +/* Stolen from ip_finish_output2
209 + * PRE : skb->dev is set to the device we are leaving by
210 + *       skb->dst is not NULL
211 + * POST: the packet is sent with the link layer header pushed
212 + *       the packet is destroyed
213 + */
214 +static void ip_direct_send(struct sk_buff *skb)
215 +{
216 +       struct dst_entry *dst = skb->dst;
217 +       struct hh_cache *hh = dst->hh;
218 +       struct net_device *dev = dst->dev;
219 +       int hh_len = LL_RESERVED_SPACE(dev);
220 +
221 +       /* Be paranoid, rather than too clever. */
222 +       if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
223 +               struct sk_buff *skb2;
224 +
225 +               skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
226 +               if (skb2 == NULL) {
227 +                       kfree_skb(skb);
228 +                       return;
229 +               }
230 +               if (skb->sk)
231 +                       skb_set_owner_w(skb2, skb->sk);
232 +               kfree_skb(skb);
233 +               skb = skb2;
234 +       }
235 +
236 +       if (hh) {
237 +               int hh_alen;
238 +
239 +               read_lock_bh(&hh->hh_lock);
240 +               hh_alen = HH_DATA_ALIGN(hh->hh_len);
241 +               memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
242 +               read_unlock_bh(&hh->hh_lock);
243 +               skb_push(skb, hh->hh_len);
244 +               hh->hh_output(skb);
245 +       } else if (dst->neighbour)
246 +               dst->neighbour->output(skb);
247 +       else {
248 +               if (net_ratelimit())
249 +                       DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n");
250 +               kfree_skb(skb);
251 +       }
252 +}
253 +
254 +
255 +/* PRE : skb->dev is set to the device we are leaving by
256 + * POST: - the packet is directly sent to the skb->dev device, without 
257 + *         pushing the link layer header.
258 + *       - the packet is destroyed
259 + */
260 +static inline int dev_direct_send(struct sk_buff *skb)
261 +{
262 +       return dev_queue_xmit(skb);
263 +}
264 +
265 +
266 +static unsigned int route_oif(const struct ipt_route_target_info *route_info,
267 +                             struct sk_buff *skb) 
268 +{
269 +       unsigned int ifindex = 0;
270 +       struct net_device *dev_out = NULL;
271 +
272 +       /* The user set the interface name to use.
273 +        * Getting the current interface index.
274 +        */
275 +       if ((dev_out = dev_get_by_name(route_info->oif))) {
276 +               ifindex = dev_out->ifindex;
277 +       } else {
278 +               /* Unknown interface name : packet dropped */
279 +               if (net_ratelimit()) 
280 +                       DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif);
281 +               return NF_DROP;
282 +       }
283 +
284 +       /* Trying the standard way of routing packets */
285 +       switch (route(skb, ifindex, route_info)) {
286 +       case 1:
287 +               dev_put(dev_out);
288 +               if (route_info->flags & IPT_ROUTE_CONTINUE)
289 +                       return IPT_CONTINUE;
290 +
291 +               ip_direct_send(skb);
292 +               return NF_STOLEN;
293 +
294 +       case 0:
295 +               /* Failed to send to oif. Trying the hard way */
296 +               if (route_info->flags & IPT_ROUTE_CONTINUE)
297 +                       return NF_DROP;
298 +
299 +               if (net_ratelimit()) 
300 +                       DEBUGP("ipt_ROUTE: forcing the use of %i\n",
301 +                              ifindex);
302 +
303 +               /* We have to force the use of an interface.
304 +                * This interface must be a tunnel interface since
305 +                * otherwise we can't guess the hw address for
306 +                * the packet. For a tunnel interface, no hw address
307 +                * is needed.
308 +                */
309 +               if ((dev_out->type != ARPHRD_TUNNEL)
310 +                   && (dev_out->type != ARPHRD_IPGRE)) {
311 +                       if (net_ratelimit()) 
312 +                               DEBUGP("ipt_ROUTE: can't guess the hw addr !\n");
313 +                       dev_put(dev_out);
314 +                       return NF_DROP;
315 +               }
316 +       
317 +               /* Send the packet. This will also free skb
318 +                * Do not go through the POST_ROUTING hook because 
319 +                * skb->dst is not set and because it will probably
320 +                * get confused by the destination IP address.
321 +                */
322 +               skb->dev = dev_out;
323 +               dev_direct_send(skb);
324 +               dev_put(dev_out);
325 +               return NF_STOLEN;
326 +               
327 +       default:
328 +               /* Unexpected error */
329 +               dev_put(dev_out);
330 +               return NF_DROP;
331 +       }
332 +}
333 +
334 +
335 +static unsigned int route_iif(const struct ipt_route_target_info *route_info,
336 +                             struct sk_buff *skb) 
337 +{
338 +       struct net_device *dev_in = NULL;
339 +
340 +       /* Getting the current interface index. */
341 +       if (!(dev_in = dev_get_by_name(route_info->iif))) {
342 +               if (net_ratelimit()) 
343 +                       DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->iif);
344 +               return NF_DROP;
345 +       }
346 +
347 +       skb->dev = dev_in;
348 +       dst_release(skb->dst);
349 +       skb->dst = NULL;
350 +
351 +       netif_rx(skb);
352 +       dev_put(dev_in);
353 +       return NF_STOLEN;
354 +}
355 +
356 +
357 +static unsigned int route_gw(const struct ipt_route_target_info *route_info,
358 +                            struct sk_buff *skb) 
359 +{
360 +       if (route(skb, 0, route_info)!=1)
361 +               return NF_DROP;
362 +
363 +       if (route_info->flags & IPT_ROUTE_CONTINUE)
364 +               return IPT_CONTINUE;
365 +
366 +       ip_direct_send(skb);
367 +       return NF_STOLEN;
368 +}
369 +
370 +
371 +/* To detect and deter routed packet loopback when using the --tee option,
372 + * we take a page out of the raw.patch book: on the copied skb, we set up
373 + * a fake ->nfct entry, pointing to the local &route_tee_track. We skip
374 + * routing packets when we see they already have that ->nfct.
375 + */
376 +
377 +static struct ip_conntrack route_tee_track;
378 +
379 +static unsigned int ipt_route_target(struct sk_buff **pskb,
380 +                                    const struct net_device *in,
381 +                                    const struct net_device *out,
382 +                                    unsigned int hooknum,
383 +                                    const void *targinfo,
384 +                                    void *userinfo)
385 +{
386 +       const struct ipt_route_target_info *route_info = targinfo;
387 +       struct sk_buff *skb = *pskb;
388 +       unsigned int res;
389 +
390 +       if (skb->nfct == &route_tee_track.ct_general) {
391 +               /* Loopback - a packet we already routed, is to be
392 +                * routed another time. Avoid that, now.
393 +                */
394 +               if (net_ratelimit()) 
395 +                       DEBUGP(KERN_DEBUG "ipt_ROUTE: loopback - DROP!\n");
396 +               return NF_DROP;
397 +       }
398 +
399 +       /* If we are at PREROUTING or INPUT hook
400 +        * the TTL isn't decreased by the IP stack
401 +        */
402 +       if (hooknum == NF_IP_PRE_ROUTING ||
403 +           hooknum == NF_IP_LOCAL_IN) {
404 +
405 +               struct iphdr *iph = skb->nh.iph;
406 +
407 +               if (iph->ttl <= 1) {
408 +                       struct rtable *rt;
409 +                       struct flowi fl = {
410 +                               .oif = 0,
411 +                               .nl_u = {
412 +                                       .ip4_u = {
413 +                                               .daddr = iph->daddr,
414 +                                               .saddr = iph->saddr,
415 +                                               .tos = RT_TOS(iph->tos),
416 +                                               .scope = ((iph->tos & RTO_ONLINK) ?
417 +                                                         RT_SCOPE_LINK :
418 +                                                         RT_SCOPE_UNIVERSE)
419 +                                       }
420 +                               } 
421 +                       };
422 +
423 +                       if (ip_route_output_key(&rt, &fl)) {
424 +                               return NF_DROP;
425 +                       }
426 +
427 +                       if (skb->dev == rt->u.dst.dev) {
428 +                               /* Drop old route. */
429 +                               dst_release(skb->dst);
430 +                               skb->dst = &rt->u.dst;
431 +
432 +                               /* this will traverse normal stack, and 
433 +                                * thus call conntrack on the icmp packet */
434 +                               icmp_send(skb, ICMP_TIME_EXCEEDED, 
435 +                                         ICMP_EXC_TTL, 0);
436 +                       }
437 +
438 +                       return NF_DROP;
439 +               }
440 +
441 +               /*
442 +                * If we are at INPUT the checksum must be recalculated since
443 +                * the length could change as the result of a defragmentation.
444 +                */
445 +               if(hooknum == NF_IP_LOCAL_IN) {
446 +                       iph->ttl = iph->ttl - 1;
447 +                       iph->check = 0;
448 +                       iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
449 +               } else {
450 +                       ip_decrease_ttl(iph);
451 +               }
452 +       }
453 +
454 +       if ((route_info->flags & IPT_ROUTE_TEE)) {
455 +               /*
456 +                * Copy the *pskb, and route the copy. Will later return
457 +                * IPT_CONTINUE for the original skb, which should continue
458 +                * on its way as if nothing happened. The copy should be
459 +                * independantly delivered to the ROUTE --gw.
460 +                */
461 +               skb = skb_copy(*pskb, GFP_ATOMIC);
462 +               if (!skb) {
463 +                       if (net_ratelimit()) 
464 +                               DEBUGP(KERN_DEBUG "ipt_ROUTE: copy failed!\n");
465 +                       return IPT_CONTINUE;
466 +               }
467 +       }
468 +
469 +       /* Tell conntrack to forget this packet since it may get confused 
470 +        * when a packet is leaving with dst address == our address.
471 +        * Good idea ? Dunno. Need advice.
472 +        *
473 +        * NEW: mark the skb with our &route_tee_track, so we avoid looping
474 +        * on any already routed packet.
475 +        */
476 +       if (!(route_info->flags & IPT_ROUTE_CONTINUE)) {
477 +               nf_conntrack_put(skb->nfct);
478 +               skb->nfct = &route_tee_track.ct_general;
479 +               skb->nfctinfo = IP_CT_NEW;
480 +               nf_conntrack_get(skb->nfct);
481 +#ifdef CONFIG_NETFILTER_DEBUG
482 +               skb->nf_debug = 0;
483 +#endif
484 +       }
485 +
486 +       if (route_info->oif[0] != '\0') {
487 +               res = route_oif(route_info, skb);
488 +       } else if (route_info->iif[0] != '\0') {
489 +               res = route_iif(route_info, skb);
490 +       } else if (route_info->gw) {
491 +               res = route_gw(route_info, skb);
492 +       } else {
493 +               if (net_ratelimit()) 
494 +                       DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
495 +               res = IPT_CONTINUE;
496 +       }
497 +
498 +       if ((route_info->flags & IPT_ROUTE_TEE))
499 +               res = IPT_CONTINUE;
500 +
501 +       return res;
502 +}
503 +
504 +
505 +static int ipt_route_checkentry(const char *tablename,
506 +                               const void *e,
507 +                               void *targinfo,
508 +                               unsigned int targinfosize,
509 +                               unsigned int hook_mask)
510 +{
511 +       if (strcmp(tablename, "mangle") != 0) {
512 +               printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n",
513 +                      tablename);
514 +               return 0;
515 +       }
516 +
517 +       if (hook_mask & ~(  (1 << NF_IP_PRE_ROUTING)
518 +                           | (1 << NF_IP_LOCAL_IN)
519 +                           | (1 << NF_IP_FORWARD)
520 +                           | (1 << NF_IP_LOCAL_OUT)
521 +                           | (1 << NF_IP_POST_ROUTING))) {
522 +               printk("ipt_ROUTE: bad hook\n");
523 +               return 0;
524 +       }
525 +
526 +       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) {
527 +               printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n",
528 +                      targinfosize,
529 +                      IPT_ALIGN(sizeof(struct ipt_route_target_info)));
530 +               return 0;
531 +       }
532 +
533 +       return 1;
534 +}
535 +
536 +
537 +static struct ipt_target ipt_route_reg = { 
538 +       .name = "ROUTE",
539 +       .target = ipt_route_target,
540 +       .checkentry = ipt_route_checkentry,
541 +       .me = THIS_MODULE,
542 +};
543 +
544 +static int __init init(void)
545 +{
546 +       /* Set up fake conntrack (stolen from raw.patch):
547 +           - to never be deleted, not in any hashes */
548 +       atomic_set(&route_tee_track.ct_general.use, 1);
549 +       /*  - and look it like as a confirmed connection */
550 +       set_bit(IPS_CONFIRMED_BIT, &route_tee_track.status);
551 +       /* Initialize fake conntrack so that NAT will skip it */
552 +       route_tee_track.status |= IPS_NAT_DONE_MASK;
553 +
554 +       return ipt_register_target(&ipt_route_reg);
555 +}
556 +
557 +
558 +static void __exit fini(void)
559 +{
560 +       ipt_unregister_target(&ipt_route_reg);
561 +}
562 +
563 +module_init(init);
564 +module_exit(fini);
565 diff -Nur --exclude '*.orig' linux.org/net/ipv6/ipv6_syms.c linux/net/ipv6/ipv6_syms.c
566 --- linux.org/net/ipv6/ipv6_syms.c      2006-05-02 23:38:44.000000000 +0200
567 +++ linux/net/ipv6/ipv6_syms.c  2006-05-04 11:20:35.000000000 +0200
568 @@ -12,6 +12,7 @@
569  EXPORT_SYMBOL(icmpv6_statistics);
570  EXPORT_SYMBOL(icmpv6_err_convert);
571  EXPORT_SYMBOL(ndisc_mc_map);
572 +EXPORT_SYMBOL(nd_tbl);
573  EXPORT_SYMBOL(register_inet6addr_notifier);
574  EXPORT_SYMBOL(unregister_inet6addr_notifier);
575  EXPORT_SYMBOL(ip6_route_output);
576 diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/Kconfig linux/net/ipv6/netfilter/Kconfig
577 --- linux.org/net/ipv6/netfilter/Kconfig        2006-05-02 23:38:44.000000000 +0200
578 +++ linux/net/ipv6/netfilter/Kconfig    2006-05-04 11:20:35.000000000 +0200
579 @@ -210,5 +210,18 @@
580           If you want to compile it as a module, say M here and read
581           <file:Documentation/modules.txt>.  If unsure, say `N'.
582  
583 +config IP6_NF_TARGET_ROUTE
584 +       tristate '    ROUTE target support'
585 +       depends on IP6_NF_MANGLE
586 +       help
587 +         This option adds a `ROUTE' target, which enables you to setup unusual
588 +         routes. The ROUTE target is also able to change the incoming interface
589 +         of a packet.
590 +       
591 +         The target can be or not a final target. It has to be used inside the 
592 +         mangle table.
593 +         
594 +         Not working as a module.
595 +
596  endmenu
597  
598 diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/Makefile linux/net/ipv6/netfilter/Makefile
599 --- linux.org/net/ipv6/netfilter/Makefile       2006-05-02 23:38:44.000000000 +0200
600 +++ linux/net/ipv6/netfilter/Makefile   2006-05-04 11:20:35.000000000 +0200
601 @@ -0,0 +0,1 @@
602 +obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o
603 diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/ip6t_ROUTE.c linux/net/ipv6/netfilter/ip6t_ROUTE.c
604 --- linux.org/net/ipv6/netfilter/ip6t_ROUTE.c   1970-01-01 01:00:00.000000000 +0100
605 +++ linux/net/ipv6/netfilter/ip6t_ROUTE.c       2006-05-04 11:20:35.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");
This page took 0.10377 seconds and 3 git commands to generate.