summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-01-29 19:08:25 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-08 12:01:48 -0800
commit418b48ea165b0b03652c85436807ac6760838c21 (patch)
tree747b0f7205b54e3f06d430e2d07d35c2903bcde7
parent0bf056904b95fa555c36eb0cfbcee9c015747f59 (diff)
downloadlinux-stable-418b48ea165b0b03652c85436807ac6760838c21.tar.gz
linux-stable-418b48ea165b0b03652c85436807ac6760838c21.tar.bz2
linux-stable-418b48ea165b0b03652c85436807ac6760838c21.zip
Netfilter: bridge: fix double POST_ROUTING invocation
[NETFILTER]: bridge: fix double POST_ROUTING invocation Upstream commit 2948d2ebbb98747b912ac6d0c864b4d02be8a6f5 The bridge code incorrectly causes two POST_ROUTING hook invocations for DNATed packets that end up on the same bridge device. This happens because packets with a changed destination address are passed to dst_output() to make them go through the neighbour output function again to build a new destination MAC address, before they will continue through the IP hooks simulated by bridge netfilter. The resulting hook order is: PREROUTING (bridge netfilter) POSTROUTING (dst_output -> ip_output) FORWARD (bridge netfilter) POSTROUTING (bridge netfilter) The deferred hooks used to abort the first POST_ROUTING invocation, but since the only thing bridge netfilter actually really wants is a new MAC address, we can avoid going through the IP stack completely by simply calling the neighbour output function directly. Tested, reported and lots of data provided by: Damien Thebault <damien.thebault@gmail.com> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--net/bridge/br_netfilter.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index fc13130035e7..ce48d8cb98e0 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -247,8 +247,9 @@ static void __br_dnat_complain(void)
* Let us first consider the case that ip_route_input() succeeds:
*
* If skb->dst->dev equals the logical bridge device the packet
- * came in on, we can consider this bridging. We then call
- * skb->dst->output() which will make the packet enter br_nf_local_out()
+ * came in on, we can consider this bridging. The packet is passed
+ * through the neighbour output function to build a new destination
+ * MAC address, which will make the packet enter br_nf_local_out()
* not much later. In that function it is assured that the iptables
* FORWARD chain is traversed for the packet.
*
@@ -285,12 +286,17 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
skb->dev = bridge_parent(skb->dev);
- if (!skb->dev)
- kfree_skb(skb);
- else {
+ if (skb->dev) {
+ struct dst_entry *dst = skb->dst;
+
nf_bridge_pull_encap_header(skb);
- skb->dst->output(skb);
+
+ if (dst->hh)
+ return neigh_hh_output(dst->hh, skb);
+ else if (dst->neighbour)
+ return dst->neighbour->output(skb);
}
+ kfree_skb(skb);
return 0;
}