[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: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f92f871989
commit
7a11b9848a
|
@ -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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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],
|
||||||
|
|
Loading…
Reference in New Issue