diff options
author | Harald Welte <laforge@netfilter.org> | 2005-08-09 22:42:34 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-29 18:36:19 -0400 |
commit | 2cc7d5730957c4a3f3659d17d2ba5e06d5581c1f (patch) | |
tree | c2c3d03d8120831d487bb8fcc73e5dcbe13aebea | |
parent | 4fdb3bb723db469717c6d38fda667d8b0fa86ebd (diff) |
[NETFILTER]: Move reroute-after-queue code up to the nf_queue layer.
The rerouting functionality is required by the core, therefore it has
to be implemented by the core and not in individual queue handlers.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netfilter.h | 11 | ||||
-rw-r--r-- | include/linux/netfilter_ipv6.h | 3 | ||||
-rw-r--r-- | net/core/netfilter.c | 66 | ||||
-rw-r--r-- | net/ipv4/netfilter.c | 64 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 27 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 7 | ||||
-rw-r--r-- | net/ipv6/netfilter.c | 62 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 24 |
8 files changed, 199 insertions, 65 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 54b97a1baba5..d163e20ca8d9 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h | |||
@@ -198,6 +198,17 @@ extern void nf_invalidate_cache(int pf); | |||
198 | Returns true or false. */ | 198 | Returns true or false. */ |
199 | extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len); | 199 | extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len); |
200 | 200 | ||
201 | struct nf_queue_rerouter { | ||
202 | void (*save)(const struct sk_buff *skb, struct nf_info *info); | ||
203 | int (*reroute)(struct sk_buff **skb, const struct nf_info *info); | ||
204 | int rer_size; | ||
205 | }; | ||
206 | |||
207 | #define nf_info_reroute(x) ((void *)x + sizeof(struct nf_info)) | ||
208 | |||
209 | extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer); | ||
210 | extern int nf_unregister_queue_rerouter(int pf); | ||
211 | |||
201 | #else /* !CONFIG_NETFILTER */ | 212 | #else /* !CONFIG_NETFILTER */ |
202 | #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) | 213 | #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) |
203 | static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} | 214 | static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} |
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index 20c069a5e4ac..5d204ee7a312 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h | |||
@@ -71,4 +71,7 @@ enum nf_ip6_hook_priorities { | |||
71 | NF_IP6_PRI_LAST = INT_MAX, | 71 | NF_IP6_PRI_LAST = INT_MAX, |
72 | }; | 72 | }; |
73 | 73 | ||
74 | int ipv6_netfilter_init(void); | ||
75 | void ipv6_netfilter_fini(void); | ||
76 | |||
74 | #endif /*__LINUX_IP6_NETFILTER_H*/ | 77 | #endif /*__LINUX_IP6_NETFILTER_H*/ |
diff --git a/net/core/netfilter.c b/net/core/netfilter.c index 9849357f6129..1ed4f3110421 100644 --- a/net/core/netfilter.c +++ b/net/core/netfilter.c | |||
@@ -53,6 +53,9 @@ static struct nf_queue_handler_t { | |||
53 | nf_queue_outfn_t outfn; | 53 | nf_queue_outfn_t outfn; |
54 | void *data; | 54 | void *data; |
55 | } queue_handler[NPROTO]; | 55 | } queue_handler[NPROTO]; |
56 | |||
57 | static struct nf_queue_rerouter *queue_rerouter; | ||
58 | |||
56 | static DEFINE_RWLOCK(queue_handler_lock); | 59 | static DEFINE_RWLOCK(queue_handler_lock); |
57 | 60 | ||
58 | int nf_register_hook(struct nf_hook_ops *reg) | 61 | int nf_register_hook(struct nf_hook_ops *reg) |
@@ -260,11 +263,34 @@ int nf_unregister_queue_handler(int pf) | |||
260 | return 0; | 263 | return 0; |
261 | } | 264 | } |
262 | 265 | ||
266 | int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer) | ||
267 | { | ||
268 | if (pf >= NPROTO) | ||
269 | return -EINVAL; | ||
270 | |||
271 | write_lock_bh(&queue_handler_lock); | ||
272 | memcpy(&queue_rerouter[pf], rer, sizeof(queue_rerouter[pf])); | ||
273 | write_unlock_bh(&queue_handler_lock); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | int nf_unregister_queue_rerouter(int pf) | ||
279 | { | ||
280 | if (pf >= NPROTO) | ||
281 | return -EINVAL; | ||
282 | |||
283 | write_lock_bh(&queue_handler_lock); | ||
284 | memset(&queue_rerouter[pf], 0, sizeof(queue_rerouter[pf])); | ||
285 | write_unlock_bh(&queue_handler_lock); | ||
286 | return 0; | ||
287 | } | ||
288 | |||
263 | /* | 289 | /* |
264 | * Any packet that leaves via this function must come back | 290 | * Any packet that leaves via this function must come back |
265 | * through nf_reinject(). | 291 | * through nf_reinject(). |
266 | */ | 292 | */ |
267 | static int nf_queue(struct sk_buff *skb, | 293 | static int nf_queue(struct sk_buff **skb, |
268 | struct list_head *elem, | 294 | struct list_head *elem, |
269 | int pf, unsigned int hook, | 295 | int pf, unsigned int hook, |
270 | struct net_device *indev, | 296 | struct net_device *indev, |
@@ -282,17 +308,17 @@ static int nf_queue(struct sk_buff *skb, | |||
282 | read_lock(&queue_handler_lock); | 308 | read_lock(&queue_handler_lock); |
283 | if (!queue_handler[pf].outfn) { | 309 | if (!queue_handler[pf].outfn) { |
284 | read_unlock(&queue_handler_lock); | 310 | read_unlock(&queue_handler_lock); |
285 | kfree_skb(skb); | 311 | kfree_skb(*skb); |
286 | return 1; | 312 | return 1; |
287 | } | 313 | } |
288 | 314 | ||
289 | info = kmalloc(sizeof(*info), GFP_ATOMIC); | 315 | info = kmalloc(sizeof(*info)+queue_rerouter[pf].rer_size, GFP_ATOMIC); |
290 | if (!info) { | 316 | if (!info) { |
291 | if (net_ratelimit()) | 317 | if (net_ratelimit()) |
292 | printk(KERN_ERR "OOM queueing packet %p\n", | 318 | printk(KERN_ERR "OOM queueing packet %p\n", |
293 | skb); | 319 | *skb); |
294 | read_unlock(&queue_handler_lock); | 320 | read_unlock(&queue_handler_lock); |
295 | kfree_skb(skb); | 321 | kfree_skb(*skb); |
296 | return 1; | 322 | return 1; |
297 | } | 323 | } |
298 | 324 | ||
@@ -311,15 +337,21 @@ static int nf_queue(struct sk_buff *skb, | |||
311 | if (outdev) dev_hold(outdev); | 337 | if (outdev) dev_hold(outdev); |
312 | 338 | ||
313 | #ifdef CONFIG_BRIDGE_NETFILTER | 339 | #ifdef CONFIG_BRIDGE_NETFILTER |
314 | if (skb->nf_bridge) { | 340 | if ((*skb)->nf_bridge) { |
315 | physindev = skb->nf_bridge->physindev; | 341 | physindev = (*skb)->nf_bridge->physindev; |
316 | if (physindev) dev_hold(physindev); | 342 | if (physindev) dev_hold(physindev); |
317 | physoutdev = skb->nf_bridge->physoutdev; | 343 | physoutdev = (*skb)->nf_bridge->physoutdev; |
318 | if (physoutdev) dev_hold(physoutdev); | 344 | if (physoutdev) dev_hold(physoutdev); |
319 | } | 345 | } |
320 | #endif | 346 | #endif |
347 | if (queue_rerouter[pf].save) | ||
348 | queue_rerouter[pf].save(*skb, info); | ||
349 | |||
350 | status = queue_handler[pf].outfn(*skb, info, queue_handler[pf].data); | ||
351 | |||
352 | if (status >= 0 && queue_rerouter[pf].reroute) | ||
353 | status = queue_rerouter[pf].reroute(skb, info); | ||
321 | 354 | ||
322 | status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data); | ||
323 | read_unlock(&queue_handler_lock); | 355 | read_unlock(&queue_handler_lock); |
324 | 356 | ||
325 | if (status < 0) { | 357 | if (status < 0) { |
@@ -332,9 +364,11 @@ static int nf_queue(struct sk_buff *skb, | |||
332 | #endif | 364 | #endif |
333 | module_put(info->elem->owner); | 365 | module_put(info->elem->owner); |
334 | kfree(info); | 366 | kfree(info); |
335 | kfree_skb(skb); | 367 | kfree_skb(*skb); |
368 | |||
336 | return 1; | 369 | return 1; |
337 | } | 370 | } |
371 | |||
338 | return 1; | 372 | return 1; |
339 | } | 373 | } |
340 | 374 | ||
@@ -365,7 +399,7 @@ next_hook: | |||
365 | ret = -EPERM; | 399 | ret = -EPERM; |
366 | } else if (verdict == NF_QUEUE) { | 400 | } else if (verdict == NF_QUEUE) { |
367 | NFDEBUG("nf_hook: Verdict = QUEUE.\n"); | 401 | NFDEBUG("nf_hook: Verdict = QUEUE.\n"); |
368 | if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn)) | 402 | if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn)) |
369 | goto next_hook; | 403 | goto next_hook; |
370 | } | 404 | } |
371 | unlock: | 405 | unlock: |
@@ -428,7 +462,7 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, | |||
428 | break; | 462 | break; |
429 | 463 | ||
430 | case NF_QUEUE: | 464 | case NF_QUEUE: |
431 | if (!nf_queue(skb, elem, info->pf, info->hook, | 465 | if (!nf_queue(&skb, elem, info->pf, info->hook, |
432 | info->indev, info->outdev, info->okfn)) | 466 | info->indev, info->outdev, info->okfn)) |
433 | goto next_hook; | 467 | goto next_hook; |
434 | break; | 468 | break; |
@@ -555,6 +589,12 @@ void __init netfilter_init(void) | |||
555 | { | 589 | { |
556 | int i, h; | 590 | int i, h; |
557 | 591 | ||
592 | queue_rerouter = kmalloc(NPROTO * sizeof(struct nf_queue_rerouter), | ||
593 | GFP_KERNEL); | ||
594 | if (!queue_rerouter) | ||
595 | panic("netfilter: cannot allocate queue rerouter array\n"); | ||
596 | memset(queue_rerouter, 0, NPROTO * sizeof(struct nf_queue_rerouter)); | ||
597 | |||
558 | for (i = 0; i < NPROTO; i++) { | 598 | for (i = 0; i < NPROTO; i++) { |
559 | for (h = 0; h < NF_MAX_HOOKS; h++) | 599 | for (h = 0; h < NF_MAX_HOOKS; h++) |
560 | INIT_LIST_HEAD(&nf_hooks[i][h]); | 600 | INIT_LIST_HEAD(&nf_hooks[i][h]); |
@@ -573,4 +613,6 @@ EXPORT_SYMBOL(nf_reinject); | |||
573 | EXPORT_SYMBOL(nf_setsockopt); | 613 | EXPORT_SYMBOL(nf_setsockopt); |
574 | EXPORT_SYMBOL(nf_unregister_hook); | 614 | EXPORT_SYMBOL(nf_unregister_hook); |
575 | EXPORT_SYMBOL(nf_unregister_queue_handler); | 615 | EXPORT_SYMBOL(nf_unregister_queue_handler); |
616 | EXPORT_SYMBOL_GPL(nf_register_queue_rerouter); | ||
617 | EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter); | ||
576 | EXPORT_SYMBOL(nf_unregister_sockopt); | 618 | EXPORT_SYMBOL(nf_unregister_sockopt); |
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 6594d1c9697e..ae0779d82c5d 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c | |||
@@ -1,10 +1,11 @@ | |||
1 | #include <linux/config.h> | 1 | /* IPv4 specific functions of netfilter core */ |
2 | 2 | ||
3 | #include <linux/config.h> | ||
3 | #ifdef CONFIG_NETFILTER | 4 | #ifdef CONFIG_NETFILTER |
4 | 5 | ||
5 | /* IPv4 specific functions of netfilter core */ | ||
6 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
7 | #include <linux/netfilter.h> | 7 | #include <linux/netfilter.h> |
8 | #include <linux/netfilter_ipv4.h> | ||
8 | 9 | ||
9 | #include <linux/tcp.h> | 10 | #include <linux/tcp.h> |
10 | #include <linux/udp.h> | 11 | #include <linux/udp.h> |
@@ -76,4 +77,63 @@ int ip_route_me_harder(struct sk_buff **pskb) | |||
76 | return 0; | 77 | return 0; |
77 | } | 78 | } |
78 | EXPORT_SYMBOL(ip_route_me_harder); | 79 | EXPORT_SYMBOL(ip_route_me_harder); |
80 | |||
81 | /* | ||
82 | * Extra routing may needed on local out, as the QUEUE target never | ||
83 | * returns control to the table. | ||
84 | */ | ||
85 | |||
86 | struct ip_rt_info { | ||
87 | u_int32_t daddr; | ||
88 | u_int32_t saddr; | ||
89 | u_int8_t tos; | ||
90 | }; | ||
91 | |||
92 | static void queue_save(const struct sk_buff *skb, struct nf_info *info) | ||
93 | { | ||
94 | struct ip_rt_info *rt_info = nf_info_reroute(info); | ||
95 | |||
96 | if (info->hook == NF_IP_LOCAL_OUT) { | ||
97 | const struct iphdr *iph = skb->nh.iph; | ||
98 | |||
99 | rt_info->tos = iph->tos; | ||
100 | rt_info->daddr = iph->daddr; | ||
101 | rt_info->saddr = iph->saddr; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | static int queue_reroute(struct sk_buff **pskb, const struct nf_info *info) | ||
106 | { | ||
107 | const struct ip_rt_info *rt_info = nf_info_reroute(info); | ||
108 | |||
109 | if (info->hook == NF_IP_LOCAL_OUT) { | ||
110 | struct iphdr *iph = (*pskb)->nh.iph; | ||
111 | |||
112 | if (!(iph->tos == rt_info->tos | ||
113 | && iph->daddr == rt_info->daddr | ||
114 | && iph->saddr == rt_info->saddr)) | ||
115 | return ip_route_me_harder(pskb); | ||
116 | } | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static struct nf_queue_rerouter ip_reroute = { | ||
121 | .rer_size = sizeof(struct ip_rt_info), | ||
122 | .save = queue_save, | ||
123 | .reroute = queue_reroute, | ||
124 | }; | ||
125 | |||
126 | static int init(void) | ||
127 | { | ||
128 | return nf_register_queue_rerouter(PF_INET, &ip_reroute); | ||
129 | } | ||
130 | |||
131 | static void fini(void) | ||
132 | { | ||
133 | nf_unregister_queue_rerouter(PF_INET); | ||
134 | } | ||
135 | |||
136 | module_init(init); | ||
137 | module_exit(fini); | ||
138 | |||
79 | #endif /* CONFIG_NETFILTER */ | 139 | #endif /* CONFIG_NETFILTER */ |
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index b237f7fcad92..78892980f42c 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c | |||
@@ -43,17 +43,10 @@ | |||
43 | #define NET_IPQ_QMAX 2088 | 43 | #define NET_IPQ_QMAX 2088 |
44 | #define NET_IPQ_QMAX_NAME "ip_queue_maxlen" | 44 | #define NET_IPQ_QMAX_NAME "ip_queue_maxlen" |
45 | 45 | ||
46 | struct ipq_rt_info { | ||
47 | __u8 tos; | ||
48 | __u32 daddr; | ||
49 | __u32 saddr; | ||
50 | }; | ||
51 | |||
52 | struct ipq_queue_entry { | 46 | struct ipq_queue_entry { |
53 | struct list_head list; | 47 | struct list_head list; |
54 | struct nf_info *info; | 48 | struct nf_info *info; |
55 | struct sk_buff *skb; | 49 | struct sk_buff *skb; |
56 | struct ipq_rt_info rt_info; | ||
57 | }; | 50 | }; |
58 | 51 | ||
59 | typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); | 52 | typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); |
@@ -305,14 +298,6 @@ ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) | |||
305 | entry->info = info; | 298 | entry->info = info; |
306 | entry->skb = skb; | 299 | entry->skb = skb; |
307 | 300 | ||
308 | if (entry->info->hook == NF_IP_LOCAL_OUT) { | ||
309 | struct iphdr *iph = skb->nh.iph; | ||
310 | |||
311 | entry->rt_info.tos = iph->tos; | ||
312 | entry->rt_info.daddr = iph->daddr; | ||
313 | entry->rt_info.saddr = iph->saddr; | ||
314 | } | ||
315 | |||
316 | nskb = ipq_build_packet_message(entry, &status); | 301 | nskb = ipq_build_packet_message(entry, &status); |
317 | if (nskb == NULL) | 302 | if (nskb == NULL) |
318 | goto err_out_free; | 303 | goto err_out_free; |
@@ -393,18 +378,6 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) | |||
393 | memcpy(e->skb->data, v->payload, v->data_len); | 378 | memcpy(e->skb->data, v->payload, v->data_len); |
394 | e->skb->ip_summed = CHECKSUM_NONE; | 379 | e->skb->ip_summed = CHECKSUM_NONE; |
395 | 380 | ||
396 | /* | ||
397 | * Extra routing may needed on local out, as the QUEUE target never | ||
398 | * returns control to the table. | ||
399 | */ | ||
400 | if (e->info->hook == NF_IP_LOCAL_OUT) { | ||
401 | struct iphdr *iph = e->skb->nh.iph; | ||
402 | |||
403 | if (!(iph->tos == e->rt_info.tos | ||
404 | && iph->daddr == e->rt_info.daddr | ||
405 | && iph->saddr == e->rt_info.saddr)) | ||
406 | return ip_route_me_harder(&e->skb); | ||
407 | } | ||
408 | return 0; | 381 | return 0; |
409 | } | 382 | } |
410 | 383 | ||
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 28d9bcab0970..574047353628 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/netdevice.h> | 44 | #include <linux/netdevice.h> |
45 | #include <linux/icmpv6.h> | 45 | #include <linux/icmpv6.h> |
46 | #include <linux/smp_lock.h> | 46 | #include <linux/smp_lock.h> |
47 | #include <linux/netfilter_ipv6.h> | ||
47 | 48 | ||
48 | #include <net/ip.h> | 49 | #include <net/ip.h> |
49 | #include <net/ipv6.h> | 50 | #include <net/ipv6.h> |
@@ -757,6 +758,9 @@ static int __init inet6_init(void) | |||
757 | err = igmp6_init(&inet6_family_ops); | 758 | err = igmp6_init(&inet6_family_ops); |
758 | if (err) | 759 | if (err) |
759 | goto igmp_fail; | 760 | goto igmp_fail; |
761 | err = ipv6_netfilter_init(); | ||
762 | if (err) | ||
763 | goto netfilter_fail; | ||
760 | /* Create /proc/foo6 entries. */ | 764 | /* Create /proc/foo6 entries. */ |
761 | #ifdef CONFIG_PROC_FS | 765 | #ifdef CONFIG_PROC_FS |
762 | err = -ENOMEM; | 766 | err = -ENOMEM; |
@@ -813,6 +817,8 @@ proc_tcp6_fail: | |||
813 | raw6_proc_exit(); | 817 | raw6_proc_exit(); |
814 | proc_raw6_fail: | 818 | proc_raw6_fail: |
815 | #endif | 819 | #endif |
820 | ipv6_netfilter_fini(); | ||
821 | netfilter_fail: | ||
816 | igmp6_cleanup(); | 822 | igmp6_cleanup(); |
817 | igmp_fail: | 823 | igmp_fail: |
818 | ndisc_cleanup(); | 824 | ndisc_cleanup(); |
@@ -852,6 +858,7 @@ static void __exit inet6_exit(void) | |||
852 | ip6_route_cleanup(); | 858 | ip6_route_cleanup(); |
853 | ipv6_packet_cleanup(); | 859 | ipv6_packet_cleanup(); |
854 | igmp6_cleanup(); | 860 | igmp6_cleanup(); |
861 | ipv6_netfilter_fini(); | ||
855 | ndisc_cleanup(); | 862 | ndisc_cleanup(); |
856 | icmpv6_cleanup(); | 863 | icmpv6_cleanup(); |
857 | #ifdef CONFIG_SYSCTL | 864 | #ifdef CONFIG_SYSCTL |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 5656d0959aba..c8daef97cf56 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -5,6 +5,8 @@ | |||
5 | 5 | ||
6 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
7 | #include <linux/ipv6.h> | 7 | #include <linux/ipv6.h> |
8 | #include <linux/netfilter.h> | ||
9 | #include <linux/netfilter_ipv6.h> | ||
8 | #include <net/dst.h> | 10 | #include <net/dst.h> |
9 | #include <net/ipv6.h> | 11 | #include <net/ipv6.h> |
10 | #include <net/ip6_route.h> | 12 | #include <net/ip6_route.h> |
@@ -40,4 +42,64 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
40 | } | 42 | } |
41 | EXPORT_SYMBOL(ip6_route_me_harder); | 43 | EXPORT_SYMBOL(ip6_route_me_harder); |
42 | 44 | ||
45 | /* | ||
46 | * Extra routing may needed on local out, as the QUEUE target never | ||
47 | * returns control to the table. | ||
48 | */ | ||
49 | |||
50 | struct ip6_rt_info { | ||
51 | struct in6_addr daddr; | ||
52 | struct in6_addr saddr; | ||
53 | }; | ||
54 | |||
55 | static void save(const struct sk_buff *skb, struct nf_info *info) | ||
56 | { | ||
57 | struct ip6_rt_info *rt_info = nf_info_reroute(info); | ||
58 | |||
59 | if (info->hook == NF_IP6_LOCAL_OUT) { | ||
60 | struct ipv6hdr *iph = skb->nh.ipv6h; | ||
61 | |||
62 | rt_info->daddr = iph->daddr; | ||
63 | rt_info->saddr = iph->saddr; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | static int reroute(struct sk_buff **pskb, const struct nf_info *info) | ||
68 | { | ||
69 | struct ip6_rt_info *rt_info = nf_info_reroute(info); | ||
70 | |||
71 | if (info->hook == NF_IP6_LOCAL_OUT) { | ||
72 | struct ipv6hdr *iph = (*pskb)->nh.ipv6h; | ||
73 | if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || | ||
74 | !ipv6_addr_equal(&iph->saddr, &rt_info->saddr)) | ||
75 | return ip6_route_me_harder(*pskb); | ||
76 | } | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static struct nf_queue_rerouter ip6_reroute = { | ||
81 | .rer_size = sizeof(struct ip6_rt_info), | ||
82 | .save = &save, | ||
83 | .reroute = &reroute, | ||
84 | }; | ||
85 | |||
86 | int __init ipv6_netfilter_init(void) | ||
87 | { | ||
88 | return nf_register_queue_rerouter(PF_INET6, &ip6_reroute); | ||
89 | } | ||
90 | |||
91 | void ipv6_netfilter_fini(void) | ||
92 | { | ||
93 | nf_unregister_queue_rerouter(PF_INET6); | ||
94 | } | ||
95 | |||
96 | #else /* CONFIG_NETFILTER */ | ||
97 | int __init ipv6_netfilter_init(void) | ||
98 | { | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | void ipv6_netfilter_fini(void) | ||
103 | { | ||
104 | } | ||
43 | #endif /* CONFIG_NETFILTER */ | 105 | #endif /* CONFIG_NETFILTER */ |
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 1c3d247a22cc..c45d8f8815de 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
@@ -47,16 +47,10 @@ | |||
47 | #define NET_IPQ_QMAX 2088 | 47 | #define NET_IPQ_QMAX 2088 |
48 | #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen" | 48 | #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen" |
49 | 49 | ||
50 | struct ipq_rt_info { | ||
51 | struct in6_addr daddr; | ||
52 | struct in6_addr saddr; | ||
53 | }; | ||
54 | |||
55 | struct ipq_queue_entry { | 50 | struct ipq_queue_entry { |
56 | struct list_head list; | 51 | struct list_head list; |
57 | struct nf_info *info; | 52 | struct nf_info *info; |
58 | struct sk_buff *skb; | 53 | struct sk_buff *skb; |
59 | struct ipq_rt_info rt_info; | ||
60 | }; | 54 | }; |
61 | 55 | ||
62 | typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); | 56 | typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); |
@@ -302,13 +296,6 @@ ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) | |||
302 | entry->info = info; | 296 | entry->info = info; |
303 | entry->skb = skb; | 297 | entry->skb = skb; |
304 | 298 | ||
305 | if (entry->info->hook == NF_IP_LOCAL_OUT) { | ||
306 | struct ipv6hdr *iph = skb->nh.ipv6h; | ||
307 | |||
308 | entry->rt_info.daddr = iph->daddr; | ||
309 | entry->rt_info.saddr = iph->saddr; | ||
310 | } | ||
311 | |||
312 | nskb = ipq_build_packet_message(entry, &status); | 299 | nskb = ipq_build_packet_message(entry, &status); |
313 | if (nskb == NULL) | 300 | if (nskb == NULL) |
314 | goto err_out_free; | 301 | goto err_out_free; |
@@ -389,17 +376,6 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) | |||
389 | memcpy(e->skb->data, v->payload, v->data_len); | 376 | memcpy(e->skb->data, v->payload, v->data_len); |
390 | e->skb->ip_summed = CHECKSUM_NONE; | 377 | e->skb->ip_summed = CHECKSUM_NONE; |
391 | 378 | ||
392 | /* | ||
393 | * Extra routing may needed on local out, as the QUEUE target never | ||
394 | * returns control to the table. | ||
395 | * Not a nice way to cmp, but works | ||
396 | */ | ||
397 | if (e->info->hook == NF_IP_LOCAL_OUT) { | ||
398 | struct ipv6hdr *iph = e->skb->nh.ipv6h; | ||
399 | if (!ipv6_addr_equal(&iph->daddr, &e->rt_info.daddr) || | ||
400 | !ipv6_addr_equal(&iph->saddr, &e->rt_info.saddr)) | ||
401 | return ip6_route_me_harder(e->skb); | ||
402 | } | ||
403 | return 0; | 379 | return 0; |
404 | } | 380 | } |
405 | 381 | ||