Skip to content

Commit

Permalink
[NETFILTER]: nf_queue: fix rerouting after packet mangling
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Feb 27, 2006
1 parent f92f871 commit 7a11b98
Showing 1 changed file with 15 additions and 7 deletions.
22 changes: 15 additions & 7 deletions net/netfilter/nf_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/seq_file.h>
#include <linux/rcupdate.h>
#include <net/protocol.h>

#include "nf_internals.h"
Expand Down Expand Up @@ -64,7 +65,7 @@ int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer)
return -EINVAL;

write_lock_bh(&queue_handler_lock);
queue_rerouter[pf] = rer;
rcu_assign_pointer(queue_rerouter[pf], rer);
write_unlock_bh(&queue_handler_lock);

return 0;
Expand All @@ -77,8 +78,9 @@ int nf_unregister_queue_rerouter(int pf)
return -EINVAL;

write_lock_bh(&queue_handler_lock);
queue_rerouter[pf] = NULL;
rcu_assign_pointer(queue_rerouter[pf], NULL);
write_unlock_bh(&queue_handler_lock);
synchronize_rcu();
return 0;
}
EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
Expand Down Expand Up @@ -114,6 +116,7 @@ int nf_queue(struct sk_buff **skb,
struct net_device *physindev = NULL;
struct net_device *physoutdev = NULL;
#endif
struct nf_queue_rerouter *rerouter;

/* QUEUE == DROP if noone is waiting, to be safe. */
read_lock(&queue_handler_lock);
Expand Down Expand Up @@ -155,15 +158,13 @@ int nf_queue(struct sk_buff **skb,
if (physoutdev) dev_hold(physoutdev);
}
#endif
if (queue_rerouter[pf])
queue_rerouter[pf]->save(*skb, info);
rerouter = rcu_dereference(queue_rerouter[pf]);
if (rerouter)
rerouter->save(*skb, info);

status = queue_handler[pf]->outfn(*skb, info, queuenum,
queue_handler[pf]->data);

if (status >= 0 && queue_rerouter[pf])
status = queue_rerouter[pf]->reroute(skb, info);

read_unlock(&queue_handler_lock);

if (status < 0) {
Expand All @@ -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 *i;
struct nf_queue_rerouter *rerouter;

rcu_read_lock();

Expand Down Expand Up @@ -225,6 +227,12 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
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) {
next_hook:
verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
Expand Down

0 comments on commit 7a11b98

Please sign in to comment.