diff options
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br_netfilter.c | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index ac47ba2ba028..bd221ad52eaf 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/netfilter_ipv6.h> | 34 | #include <linux/netfilter_ipv6.h> |
35 | #include <linux/netfilter_arp.h> | 35 | #include <linux/netfilter_arp.h> |
36 | #include <linux/in_route.h> | 36 | #include <linux/in_route.h> |
37 | #include <linux/inetdevice.h> | ||
37 | 38 | ||
38 | #include <net/ip.h> | 39 | #include <net/ip.h> |
39 | #include <net/ipv6.h> | 40 | #include <net/ipv6.h> |
@@ -221,10 +222,14 @@ static void __br_dnat_complain(void) | |||
221 | * | 222 | * |
222 | * Otherwise, the packet is considered to be routed and we just | 223 | * Otherwise, the packet is considered to be routed and we just |
223 | * change the destination MAC address so that the packet will | 224 | * change the destination MAC address so that the packet will |
224 | * later be passed up to the IP stack to be routed. | 225 | * later be passed up to the IP stack to be routed. For a redirected |
226 | * packet, ip_route_input() will give back the localhost as output device, | ||
227 | * which differs from the bridge device. | ||
225 | * | 228 | * |
226 | * Let us now consider the case that ip_route_input() fails: | 229 | * Let us now consider the case that ip_route_input() fails: |
227 | * | 230 | * |
231 | * This can be because the destination address is martian, in which case | ||
232 | * the packet will be dropped. | ||
228 | * After a "echo '0' > /proc/sys/net/ipv4/ip_forward" ip_route_input() | 233 | * After a "echo '0' > /proc/sys/net/ipv4/ip_forward" ip_route_input() |
229 | * will fail, while __ip_route_output_key() will return success. The source | 234 | * will fail, while __ip_route_output_key() will return success. The source |
230 | * address for __ip_route_output_key() is set to zero, so __ip_route_output_key | 235 | * address for __ip_route_output_key() is set to zero, so __ip_route_output_key |
@@ -237,7 +242,8 @@ static void __br_dnat_complain(void) | |||
237 | * | 242 | * |
238 | * --Lennert, 20020411 | 243 | * --Lennert, 20020411 |
239 | * --Bart, 20020416 (updated) | 244 | * --Bart, 20020416 (updated) |
240 | * --Bart, 20021007 (updated) */ | 245 | * --Bart, 20021007 (updated) |
246 | * --Bart, 20062711 (updated) */ | ||
241 | static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) | 247 | static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) |
242 | { | 248 | { |
243 | if (skb->pkt_type == PACKET_OTHERHOST) { | 249 | if (skb->pkt_type == PACKET_OTHERHOST) { |
@@ -264,15 +270,15 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) | |||
264 | struct net_device *dev = skb->dev; | 270 | struct net_device *dev = skb->dev; |
265 | struct iphdr *iph = skb->nh.iph; | 271 | struct iphdr *iph = skb->nh.iph; |
266 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; | 272 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; |
273 | int err; | ||
267 | 274 | ||
268 | if (nf_bridge->mask & BRNF_PKT_TYPE) { | 275 | if (nf_bridge->mask & BRNF_PKT_TYPE) { |
269 | skb->pkt_type = PACKET_OTHERHOST; | 276 | skb->pkt_type = PACKET_OTHERHOST; |
270 | nf_bridge->mask ^= BRNF_PKT_TYPE; | 277 | nf_bridge->mask ^= BRNF_PKT_TYPE; |
271 | } | 278 | } |
272 | nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; | 279 | nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; |
273 | |||
274 | if (dnat_took_place(skb)) { | 280 | if (dnat_took_place(skb)) { |
275 | if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev)) { | 281 | if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) { |
276 | struct rtable *rt; | 282 | struct rtable *rt; |
277 | struct flowi fl = { | 283 | struct flowi fl = { |
278 | .nl_u = { | 284 | .nl_u = { |
@@ -283,19 +289,33 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) | |||
283 | }, | 289 | }, |
284 | .proto = 0, | 290 | .proto = 0, |
285 | }; | 291 | }; |
292 | struct in_device *in_dev = in_dev_get(dev); | ||
293 | |||
294 | /* If err equals -EHOSTUNREACH the error is due to a | ||
295 | * martian destination or due to the fact that | ||
296 | * forwarding is disabled. For most martian packets, | ||
297 | * ip_route_output_key() will fail. It won't fail for 2 types of | ||
298 | * martian destinations: loopback destinations and destination | ||
299 | * 0.0.0.0. In both cases the packet will be dropped because the | ||
300 | * destination is the loopback device and not the bridge. */ | ||
301 | if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev)) | ||
302 | goto free_skb; | ||
286 | 303 | ||
287 | if (!ip_route_output_key(&rt, &fl)) { | 304 | if (!ip_route_output_key(&rt, &fl)) { |
288 | /* - Bridged-and-DNAT'ed traffic doesn't | 305 | /* - Bridged-and-DNAT'ed traffic doesn't |
289 | * require ip_forwarding. | 306 | * require ip_forwarding. */ |
290 | * - Deal with redirected traffic. */ | 307 | if (((struct dst_entry *)rt)->dev == dev) { |
291 | if (((struct dst_entry *)rt)->dev == dev || | ||
292 | rt->rt_type == RTN_LOCAL) { | ||
293 | skb->dst = (struct dst_entry *)rt; | 308 | skb->dst = (struct dst_entry *)rt; |
294 | goto bridged_dnat; | 309 | goto bridged_dnat; |
295 | } | 310 | } |
311 | /* we are sure that forwarding is disabled, so printing | ||
312 | * this message is no problem. Note that the packet could | ||
313 | * still have a martian destination address, in which case | ||
314 | * the packet could be dropped even if forwarding were enabled */ | ||
296 | __br_dnat_complain(); | 315 | __br_dnat_complain(); |
297 | dst_release((struct dst_entry *)rt); | 316 | dst_release((struct dst_entry *)rt); |
298 | } | 317 | } |
318 | free_skb: | ||
299 | kfree_skb(skb); | 319 | kfree_skb(skb); |
300 | return 0; | 320 | return 0; |
301 | } else { | 321 | } else { |