GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / net / ipv6 / netfilter / ip6t_ROUTE.c
blobfe474bb3c0171d158551e5cd70a0c6fc0a70112d
1 /*
2 * This implements the ROUTE v6 target, which enables you to setup unusual
3 * routes not supported by the standard kernel routing table.
5 * Copyright (C) 2003 Cedric de Launois <delaunois@info.ucl.ac.be>
7 * v 1.1 2004/11/23
9 * This software is distributed under GNU GPL v2, 1991
12 #include <linux/module.h>
13 #include <linux/skbuff.h>
14 #include <linux/version.h>
16 #include <linux/ipv6.h>
17 #include <linux/netfilter_ipv6/ip6_tables.h>
18 #include <linux/netfilter_ipv6/ip6t_ROUTE.h>
19 #include <linux/netdevice.h>
20 #include <linux/version.h>
21 #include <net/ipv6.h>
22 #include <net/ndisc.h>
23 #include <net/ip6_route.h>
24 #include <linux/icmpv6.h>
26 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
27 #define ipv6_hdr(s) (s->nh.ipv6h)
28 #endif
30 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
31 #include <net/net_namespace.h>
32 #endif
34 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
35 #define NF_INET_PRE_ROUTING NF_IP6_PRE_ROUTING
36 #define NF_INET_LOCAL_IN NF_IP6_LOCAL_IN
37 #define NF_INET_FORWARD NF_IP6_FORWARD
38 #define NF_INET_LOCAL_OUT NF_IP6_LOCAL_OUT
39 #define NF_INET_POST_ROUTING NF_IP6_POST_ROUTING
40 #endif
42 #if 1
43 #define DEBUGP printk
44 #else
45 #define DEBUGP(format, args...)
46 #endif
48 #define NIP6(addr) \
49 ntohs((addr).s6_addr16[0]), \
50 ntohs((addr).s6_addr16[1]), \
51 ntohs((addr).s6_addr16[2]), \
52 ntohs((addr).s6_addr16[3]), \
53 ntohs((addr).s6_addr16[4]), \
54 ntohs((addr).s6_addr16[5]), \
55 ntohs((addr).s6_addr16[6]), \
56 ntohs((addr).s6_addr16[7])
58 /* Route the packet according to the routing keys specified in
59 * route_info. Keys are :
60 * - ifindex :
61 * 0 if no oif preferred,
62 * otherwise set to the index of the desired oif
63 * - route_info->gw :
64 * 0 if no gateway specified,
65 * otherwise set to the next host to which the pkt must be routed
66 * If success, skb->dev is the output device to which the packet must
67 * be sent and skb->dst is not NULL
69 * RETURN: 1 if the packet was succesfully routed to the
70 * destination desired
71 * 0 if the kernel routing table could not route the packet
72 * according to the keys specified
74 static int
75 route6(struct sk_buff *skb,
76 unsigned int ifindex,
77 const struct ip6t_route_target_info *route_info)
79 struct rt6_info *rt = NULL;
80 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
81 struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
83 DEBUGP("ip6t_ROUTE: called with: ");
84 DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
85 DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
86 DEBUGP("OUT=%s\n", route_info->oif);
88 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
89 if (ipv6_addr_any(gw))
90 rt = rt6_lookup(&init_net, &ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
91 else
92 rt = rt6_lookup(&init_net, gw, &ipv6h->saddr, ifindex, 1);
93 #else
94 if (ipv6_addr_any(gw))
95 rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
96 else
97 rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
98 #endif
100 if (!rt)
101 goto no_route;
103 DEBUGP("ip6t_ROUTE: routing gives: ");
104 DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
105 DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
106 DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
108 if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
109 goto wrong_route;
111 if (!rt->rt6i_nexthop) {
112 DEBUGP("ip6t_ROUTE: discovering neighbor\n");
113 rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
116 /* Drop old route. */
117 //dst_release(skb->dst);
118 //skb->dst = &rt->u.dst;
119 skb->dev = rt->rt6i_dev;
120 return 1;
122 wrong_route:
123 dst_release(&rt->dst);
124 no_route:
125 if (!net_ratelimit())
126 return 0;
128 printk("ip6t_ROUTE: no explicit route found ");
129 if (ifindex)
130 printk("via interface %s ", route_info->oif);
131 if (!ipv6_addr_any(gw))
132 printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
133 printk("\n");
134 return 0;
138 /* Stolen from ip6_output_finish
139 * PRE : skb->dev is set to the device we are leaving by
140 * skb->dst is not NULL
141 * POST: the packet is sent with the link layer header pushed
142 * the packet is destroyed
144 static void ip_direct_send(struct sk_buff *skb)
146 struct dst_entry *dst = skb_dst(skb);
147 struct hh_cache *hh = dst->hh;
148 unsigned seq;
150 if (hh) {
151 do {
152 seq = read_seqbegin(&hh->hh_lock);
153 memcpy(skb->data - 16, hh->hh_data, 16);
154 } while (read_seqretry(&hh->hh_lock, seq));
155 skb_push(skb, hh->hh_len);
156 hh->hh_output(skb);
157 } else if (dst->neighbour)
158 dst->neighbour->output(skb);
159 else {
160 if (net_ratelimit())
161 DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n");
162 kfree_skb(skb);
167 static unsigned int
168 route6_oif(const struct ip6t_route_target_info *route_info,
169 struct sk_buff *skb)
171 unsigned int ifindex = 0;
172 struct net_device *dev_out = NULL;
174 /* The user set the interface name to use.
175 * Getting the current interface index.
177 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
178 if ((dev_out = dev_get_by_name(&init_net, route_info->oif))) {
179 #else
180 if ((dev_out = dev_get_by_name(route_info->oif))) {
181 #endif
182 ifindex = dev_out->ifindex;
183 } else {
184 /* Unknown interface name : packet dropped */
185 if (net_ratelimit())
186 DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
188 if (route_info->flags & IP6T_ROUTE_CONTINUE)
189 return IP6T_CONTINUE;
190 else
191 return NF_DROP;
194 /* Trying the standard way of routing packets */
195 if (route6(skb, ifindex, route_info)) {
196 dev_put(dev_out);
197 if (route_info->flags & IP6T_ROUTE_CONTINUE)
198 return IP6T_CONTINUE;
200 ip_direct_send(skb);
201 return NF_STOLEN;
202 } else
203 return NF_DROP;
207 static unsigned int
208 route6_gw(const struct ip6t_route_target_info *route_info,
209 struct sk_buff *skb)
211 if (route6(skb, 0, route_info)) {
212 if (route_info->flags & IP6T_ROUTE_CONTINUE)
213 return IP6T_CONTINUE;
215 ip_direct_send(skb);
216 return NF_STOLEN;
217 } else
218 return NF_DROP;
221 static unsigned int
222 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
223 target(struct sk_buff **pskb,
224 unsigned int hooknum,
225 const struct net_device *in,
226 const struct net_device *out,
227 const void *targinfo,
228 void *userinfo)
229 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
230 target(struct sk_buff **pskb,
231 const struct net_device *in,
232 const struct net_device *out,
233 unsigned int hooknum,
234 const void *targinfo,
235 void *userinfo)
236 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
237 target(struct sk_buff **pskb,
238 const struct net_device *in,
239 const struct net_device *out,
240 unsigned int hooknum,
241 const struct xt_target *target,
242 const void *targinfo,
243 void *userinfo)
244 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
245 target(struct sk_buff **pskb,
246 const struct net_device *in,
247 const struct net_device *out,
248 unsigned int hooknum,
249 const struct xt_target *target,
250 const void *targinfo)
251 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
252 target(struct sk_buff *skb,
253 const struct net_device *in,
254 const struct net_device *out,
255 unsigned int hooknum,
256 const struct xt_target *target,
257 const void *targinfo)
258 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
259 target(struct sk_buff *skb,
260 const struct xt_target_param *par)
261 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) */
262 target(struct sk_buff *skb,
263 const struct xt_action_param *par)
264 #endif
266 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
267 const struct ip6t_route_target_info *route_info = targinfo;
268 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
269 const struct ip6t_route_target_info *route_info = par->targinfo;
270 unsigned int hooknum = par->hooknum;
271 #else
272 const struct ip6t_route_target_info *route_info = par->targinfo;
273 unsigned int hooknum = par->hooknum;
274 #endif
275 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
276 struct sk_buff *skb = *pskb;
277 #endif
278 struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
279 unsigned int res;
281 if (route_info->flags & IP6T_ROUTE_CONTINUE)
282 goto do_it;
284 /* If we are at PREROUTING or INPUT hook
285 * the TTL isn't decreased by the IP stack
287 if (hooknum == NF_INET_PRE_ROUTING ||
288 hooknum == NF_INET_LOCAL_IN) {
290 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
292 if (ipv6h->hop_limit <= 1) {
293 /* Force OUTPUT device used as source address */
294 skb->dev = skb_dst(skb)->dev;
296 icmpv6_send(skb, ICMPV6_TIME_EXCEED,
297 ICMPV6_EXC_HOPLIMIT, 0);
299 return NF_DROP;
302 ipv6h->hop_limit--;
305 if ((route_info->flags & IP6T_ROUTE_TEE)) {
307 * Copy the skb, and route the copy. Will later return
308 * IP6T_CONTINUE for the original skb, which should continue
309 * on its way as if nothing happened. The copy should be
310 * independantly delivered to the ROUTE --gw.
312 skb = skb_copy(skb, GFP_ATOMIC);
313 if (!skb) {
314 if (net_ratelimit())
315 DEBUGP(KERN_DEBUG "ip6t_ROUTE: copy failed!\n");
316 return IP6T_CONTINUE;
320 do_it:
321 if (route_info->oif[0]) {
322 res = route6_oif(route_info, skb);
323 } else if (!ipv6_addr_any(gw)) {
324 res = route6_gw(route_info, skb);
325 } else {
326 if (net_ratelimit())
327 DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
328 res = IP6T_CONTINUE;
331 if ((route_info->flags & IP6T_ROUTE_TEE))
332 res = IP6T_CONTINUE;
334 return res;
338 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
339 static int
340 checkentry(const char *tablename,
341 const struct ip6t_entry *e,
342 void *targinfo,
343 unsigned int targinfosize,
344 unsigned int hook_mask)
345 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
346 static int
347 checkentry(const char *tablename,
348 const void *e,
349 void *targinfo,
350 unsigned int targinfosize,
351 unsigned int hook_mask)
352 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
353 static int
354 checkentry(const char *tablename,
355 const void *e,
356 const struct xt_target *target,
357 void *targinfo,
358 unsigned int targinfosize,
359 unsigned int hook_mask)
360 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
361 static int
362 checkentry(const char *tablename,
363 const void *e,
364 const struct xt_target *target,
365 void *targinfo,
366 unsigned int hook_mask)
367 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
368 static bool
369 checkentry(const char *tablename,
370 const void *e,
371 const struct xt_target *target,
372 void *targinfo,
373 unsigned int hook_mask)
374 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
375 static bool
376 checkentry(const struct xt_tgchk_param *par)
377 #endif
379 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
380 const char *tablename = par->table;
381 #endif
383 if (strcmp(tablename, "mangle") != 0) {
384 printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
385 return 0;
388 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
389 if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) {
390 printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n",
391 targinfosize,
392 IP6T_ALIGN(sizeof(struct ip6t_route_target_info)));
393 return 0;
395 #endif
397 return 1;
400 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
401 static struct xt_target ip6t_route_reg = {
402 #else
403 static struct ip6t_target ip6t_route_reg = {
404 #endif
405 .name = "ROUTE",
406 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
407 .family = AF_INET6,
408 #endif
409 .target = target,
410 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
411 .targetsize = sizeof(struct ip6t_route_target_info),
412 #endif
413 .checkentry = checkentry,
414 .me = THIS_MODULE
418 static int __init init(void)
420 printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
421 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
422 if (xt_register_target(&ip6t_route_reg))
423 #else
424 if (ip6t_register_target(&ip6t_route_reg))
425 #endif
426 return -EINVAL;
428 return 0;
432 static void __exit fini(void)
434 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
435 xt_unregister_target(&ip6t_route_reg);
436 #else
437 ip6t_unregister_target(&ip6t_route_reg);
438 #endif
441 module_init(init);
442 module_exit(fini);
443 MODULE_LICENSE("GPL");