aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/netfilter.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@netfilter.org>2005-08-09 19:42:34 -0700
committerDavid S. Miller <davem@sunset.davemloft.net>2005-08-29 15:36:19 -0700
commit2cc7d5730957c4a3f3659d17d2ba5e06d5581c1f (patch)
treec2c3d03d8120831d487bb8fcc73e5dcbe13aebea /net/ipv4/netfilter.c
parent[NETLINK]: Add properly module refcounting for kernel netlink sockets. (diff)
downloadlinux-dev-2cc7d5730957c4a3f3659d17d2ba5e06d5581c1f.tar.xz
linux-dev-2cc7d5730957c4a3f3659d17d2ba5e06d5581c1f.zip
[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.c64
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 */