Commit 7a11b984 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[NETFILTER]: nf_queue: fix rerouting after packet mangling

Packets should be rerouted when they come back from userspace, not before.
Also move the queue_rerouters to RCU to avoid taking the queue_handler_lock
for each reinjected packet.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f92f8719
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/rcupdate.h>
#include <net/protocol.h> #include <net/protocol.h>
#include "nf_internals.h" #include "nf_internals.h"
...@@ -64,7 +65,7 @@ int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer) ...@@ -64,7 +65,7 @@ int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer)
return -EINVAL; return -EINVAL;
write_lock_bh(&queue_handler_lock); write_lock_bh(&queue_handler_lock);
queue_rerouter[pf] = rer; rcu_assign_pointer(queue_rerouter[pf], rer);
write_unlock_bh(&queue_handler_lock); write_unlock_bh(&queue_handler_lock);
return 0; return 0;
...@@ -77,8 +78,9 @@ int nf_unregister_queue_rerouter(int pf) ...@@ -77,8 +78,9 @@ int nf_unregister_queue_rerouter(int pf)
return -EINVAL; return -EINVAL;
write_lock_bh(&queue_handler_lock); write_lock_bh(&queue_handler_lock);
queue_rerouter[pf] = NULL; rcu_assign_pointer(queue_rerouter[pf], NULL);
write_unlock_bh(&queue_handler_lock); write_unlock_bh(&queue_handler_lock);
synchronize_rcu();
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter); EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
...@@ -114,6 +116,7 @@ int nf_queue(struct sk_buff **skb, ...@@ -114,6 +116,7 @@ int nf_queue(struct sk_buff **skb,
struct net_device *physindev = NULL; struct net_device *physindev = NULL;
struct net_device *physoutdev = NULL; struct net_device *physoutdev = NULL;
#endif #endif
struct nf_queue_rerouter *rerouter;
/* QUEUE == DROP if noone is waiting, to be safe. */ /* QUEUE == DROP if noone is waiting, to be safe. */
read_lock(&queue_handler_lock); read_lock(&queue_handler_lock);
...@@ -155,15 +158,13 @@ int nf_queue(struct sk_buff **skb, ...@@ -155,15 +158,13 @@ int nf_queue(struct sk_buff **skb,
if (physoutdev) dev_hold(physoutdev); if (physoutdev) dev_hold(physoutdev);
} }
#endif #endif
if (queue_rerouter[pf]) rerouter = rcu_dereference(queue_rerouter[pf]);
queue_rerouter[pf]->save(*skb, info); if (rerouter)
rerouter->save(*skb, info);
status = queue_handler[pf]->outfn(*skb, info, queuenum, status = queue_handler[pf]->outfn(*skb, info, queuenum,
queue_handler[pf]->data); queue_handler[pf]->data);
if (status >= 0 && queue_rerouter[pf])
status = queue_rerouter[pf]->reroute(skb, info);
read_unlock(&queue_handler_lock); read_unlock(&queue_handler_lock);
if (status < 0) { if (status < 0) {
...@@ -189,6 +190,7 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, ...@@ -189,6 +190,7 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
{ {
struct list_head *elem = &info->elem->list; struct list_head *elem = &info->elem->list;
struct list_head *i; struct list_head *i;
struct nf_queue_rerouter *rerouter;
rcu_read_lock(); rcu_read_lock();
...@@ -225,6 +227,12 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, ...@@ -225,6 +227,12 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
verdict = NF_ACCEPT; verdict = NF_ACCEPT;
} }
if (verdict == NF_ACCEPT) {
rerouter = rcu_dereference(queue_rerouter[info->pf]);
if (rerouter && rerouter->reroute(&skb, info) < 0)
verdict = NF_DROP;
}
if (verdict == NF_ACCEPT) { if (verdict == NF_ACCEPT) {
next_hook: next_hook:
verdict = nf_iterate(&nf_hooks[info->pf][info->hook], verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment