[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>
This commit is contained in:
Harald Welte
2005-08-09 19:42:34 -07:00
committed by David S. Miller
parent 4fdb3bb723
commit 2cc7d57309
8 changed files with 199 additions and 65 deletions

View File

@ -44,6 +44,7 @@
#include <linux/netdevice.h>
#include <linux/icmpv6.h>
#include <linux/smp_lock.h>
#include <linux/netfilter_ipv6.h>
#include <net/ip.h>
#include <net/ipv6.h>
@ -757,6 +758,9 @@ static int __init inet6_init(void)
err = igmp6_init(&inet6_family_ops);
if (err)
goto igmp_fail;
err = ipv6_netfilter_init();
if (err)
goto netfilter_fail;
/* Create /proc/foo6 entries. */
#ifdef CONFIG_PROC_FS
err = -ENOMEM;
@ -813,6 +817,8 @@ proc_tcp6_fail:
raw6_proc_exit();
proc_raw6_fail:
#endif
ipv6_netfilter_fini();
netfilter_fail:
igmp6_cleanup();
igmp_fail:
ndisc_cleanup();
@ -852,6 +858,7 @@ static void __exit inet6_exit(void)
ip6_route_cleanup();
ipv6_packet_cleanup();
igmp6_cleanup();
ipv6_netfilter_fini();
ndisc_cleanup();
icmpv6_cleanup();
#ifdef CONFIG_SYSCTL

View File

@ -5,6 +5,8 @@
#include <linux/kernel.h>
#include <linux/ipv6.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
#include <net/dst.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
@ -40,4 +42,64 @@ int ip6_route_me_harder(struct sk_buff *skb)
}
EXPORT_SYMBOL(ip6_route_me_harder);
/*
* Extra routing may needed on local out, as the QUEUE target never
* returns control to the table.
*/
struct ip6_rt_info {
struct in6_addr daddr;
struct in6_addr saddr;
};
static void save(const struct sk_buff *skb, struct nf_info *info)
{
struct ip6_rt_info *rt_info = nf_info_reroute(info);
if (info->hook == NF_IP6_LOCAL_OUT) {
struct ipv6hdr *iph = skb->nh.ipv6h;
rt_info->daddr = iph->daddr;
rt_info->saddr = iph->saddr;
}
}
static int reroute(struct sk_buff **pskb, const struct nf_info *info)
{
struct ip6_rt_info *rt_info = nf_info_reroute(info);
if (info->hook == NF_IP6_LOCAL_OUT) {
struct ipv6hdr *iph = (*pskb)->nh.ipv6h;
if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
!ipv6_addr_equal(&iph->saddr, &rt_info->saddr))
return ip6_route_me_harder(*pskb);
}
return 0;
}
static struct nf_queue_rerouter ip6_reroute = {
.rer_size = sizeof(struct ip6_rt_info),
.save = &save,
.reroute = &reroute,
};
int __init ipv6_netfilter_init(void)
{
return nf_register_queue_rerouter(PF_INET6, &ip6_reroute);
}
void ipv6_netfilter_fini(void)
{
nf_unregister_queue_rerouter(PF_INET6);
}
#else /* CONFIG_NETFILTER */
int __init ipv6_netfilter_init(void)
{
return 0;
}
void ipv6_netfilter_fini(void)
{
}
#endif /* CONFIG_NETFILTER */

View File

@ -47,16 +47,10 @@
#define NET_IPQ_QMAX 2088
#define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
struct ipq_rt_info {
struct in6_addr daddr;
struct in6_addr saddr;
};
struct ipq_queue_entry {
struct list_head list;
struct nf_info *info;
struct sk_buff *skb;
struct ipq_rt_info rt_info;
};
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)
entry->info = info;
entry->skb = skb;
if (entry->info->hook == NF_IP_LOCAL_OUT) {
struct ipv6hdr *iph = skb->nh.ipv6h;
entry->rt_info.daddr = iph->daddr;
entry->rt_info.saddr = iph->saddr;
}
nskb = ipq_build_packet_message(entry, &status);
if (nskb == NULL)
goto err_out_free;
@ -389,17 +376,6 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
memcpy(e->skb->data, v->payload, v->data_len);
e->skb->ip_summed = CHECKSUM_NONE;
/*
* Extra routing may needed on local out, as the QUEUE target never
* returns control to the table.
* Not a nice way to cmp, but works
*/
if (e->info->hook == NF_IP_LOCAL_OUT) {
struct ipv6hdr *iph = e->skb->nh.ipv6h;
if (!ipv6_addr_equal(&iph->daddr, &e->rt_info.daddr) ||
!ipv6_addr_equal(&iph->saddr, &e->rt_info.saddr))
return ip6_route_me_harder(e->skb);
}
return 0;
}