diff options
author | Patrick McHardy <kaber@trash.net> | 2008-01-11 21:02:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-11 21:02:18 -0500 |
commit | 2948d2ebbb98747b912ac6d0c864b4d02be8a6f5 (patch) | |
tree | 64e0eec6a3a2c91345d5eb7a00193e94782c2db9 /net/bridge | |
parent | 0ff4d77bd9fe86ca1bc7f44839d79f8a349a62f0 (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/bridge')
-rw-r--r-- | net/bridge/br_netfilter.c | 18 |
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 | ||