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 /net/ipv6 | |
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>
Diffstat (limited to 'net/ipv6')
-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 |
3 files changed, 69 insertions, 24 deletions
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 | ||