diff options
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 | ||
