diff options
author | Harald Welte <laforge@netfilter.org> | 2005-08-09 19:42:34 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-29 15:36:19 -0700 |
commit | 2cc7d5730957c4a3f3659d17d2ba5e06d5581c1f (patch) | |
tree | c2c3d03d8120831d487bb8fcc73e5dcbe13aebea /net/ipv4/netfilter.c | |
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/ipv4/netfilter.c')
-rw-r--r-- | net/ipv4/netfilter.c | 64 |
1 files changed, 62 insertions, 2 deletions
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 @@ -#include <linux/config.h> +/* IPv4 specific functions of netfilter core */ +#include <linux/config.h> #ifdef CONFIG_NETFILTER -/* IPv4 specific functions of netfilter core */ #include <linux/kernel.h> #include <linux/netfilter.h> +#include <linux/netfilter_ipv4.h> #include <linux/tcp.h> #include <linux/udp.h> @@ -76,4 +77,63 @@ int ip_route_me_harder(struct sk_buff **pskb) return 0; } EXPORT_SYMBOL(ip_route_me_harder); + +/* + * Extra routing may needed on local out, as the QUEUE target never + * returns control to the table. + */ + +struct ip_rt_info { + u_int32_t daddr; + u_int32_t saddr; + u_int8_t tos; +}; + +static void queue_save(const struct sk_buff *skb, struct nf_info *info) +{ + struct ip_rt_info *rt_info = nf_info_reroute(info); + + if (info->hook == NF_IP_LOCAL_OUT) { + const struct iphdr *iph = skb->nh.iph; + + rt_info->tos = iph->tos; + rt_info->daddr = iph->daddr; + rt_info->saddr = iph->saddr; + } +} + +static int queue_reroute(struct sk_buff **pskb, const struct nf_info *info) +{ + const struct ip_rt_info *rt_info = nf_info_reroute(info); + + if (info->hook == NF_IP_LOCAL_OUT) { + struct iphdr *iph = (*pskb)->nh.iph; + + if (!(iph->tos == rt_info->tos + && iph->daddr == rt_info->daddr + && iph->saddr == rt_info->saddr)) + return ip_route_me_harder(pskb); + } + return 0; +} + +static struct nf_queue_rerouter ip_reroute = { + .rer_size = sizeof(struct ip_rt_info), + .save = queue_save, + .reroute = queue_reroute, +}; + +static int init(void) +{ + return nf_register_queue_rerouter(PF_INET, &ip_reroute); +} + +static void fini(void) +{ + nf_unregister_queue_rerouter(PF_INET); +} + +module_init(init); +module_exit(fini); + #endif /* CONFIG_NETFILTER */ |