aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBart De Schuymer <bdschuym@pandora.be>2006-12-05 16:45:21 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-06 21:39:06 -0500
commitf216f082b2b37c4943f1e7c393e2786648d48f6f (patch)
tree28a97b72a7568f0428ebbe77228b1ac5d7f29eb1
parentece006416d4fb472f4d2114feede5665cff971b2 (diff)
[NETFILTER]: bridge netfilter: deal with martians correctly
The attached patch resolves an issue where a IP DNATed packet with a martian source is forwarded while it's better to drop it. It also resolves messages complaining about ip forwarding being disabled while it's actually enabled. Thanks to lepton <ytht.net@gmail.com> for reporting this problem. This is probably a candidate for the -stable release. Signed-off-by: Bart De Schuymer <bdschuym@pandora.be> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/bridge/br_netfilter.c36
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) */
241static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) 247static 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 }
318free_skb:
299 kfree_skb(skb); 319 kfree_skb(skb);
300 return 0; 320 return 0;
301 } else { 321 } else {