aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-01-11 21:02:18 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-11 21:02:18 -0500
commit2948d2ebbb98747b912ac6d0c864b4d02be8a6f5 (patch)
tree64e0eec6a3a2c91345d5eb7a00193e94782c2db9 /net
parent0ff4d77bd9fe86ca1bc7f44839d79f8a349a62f0 (diff)
[NETFILTER]: bridge: fix double POST_ROUTING invocation
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>
Diffstat (limited to 'net')
-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 c1757c79dfbb..5d8b939eded1 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -247,8 +247,9 @@ static void __br_dnat_complain(void)
247 * Let us first consider the case that ip_route_input() succeeds: 247 * Let us first consider the case that ip_route_input() succeeds:
248 * 248 *
249 * If skb->dst->dev equals the logical bridge device the packet 249 * If skb->dst->dev equals the logical bridge device the packet
250 * came in on, we can consider this bridging. We then call 250 * came in on, we can consider this bridging. The packet is passed
251 * skb->dst->output() which will make the packet enter br_nf_local_out() 251 * through the neighbour output function to build a new destination
252 * MAC address, which will make the packet enter br_nf_local_out()
252 * not much later. In that function it is assured that the iptables 253 * not much later. In that function it is assured that the iptables
253 * FORWARD chain is traversed for the packet. 254 * FORWARD chain is traversed for the packet.
254 * 255 *
@@ -285,12 +286,17 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
285 skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; 286 skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
286 287
287 skb->dev = bridge_parent(skb->dev); 288 skb->dev = bridge_parent(skb->dev);
288 if (!skb->dev) 289 if (skb->dev) {
289 kfree_skb(skb); 290 struct dst_entry *dst = skb->dst;
290 else { 291
291 nf_bridge_pull_encap_header(skb); 292 nf_bridge_pull_encap_header(skb);
292 skb->dst->output(skb); 293
294 if (dst->hh)
295 return neigh_hh_output(dst->hh, skb);
296 else if (dst->neighbour)
297 return dst->neighbour->output(skb);
293 } 298 }
299 kfree_skb(skb);
294 return 0; 300 return 0;
295} 301}
296 302