diff options
| -rw-r--r-- | net/bridge/br_netfilter.c | 53 |
1 files changed, 38 insertions, 15 deletions
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 7cac3fb9f809..b5018166b0e5 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
| @@ -51,9 +51,6 @@ | |||
| 51 | #define store_orig_dstaddr(skb) (skb_origaddr(skb) = (skb)->nh.iph->daddr) | 51 | #define store_orig_dstaddr(skb) (skb_origaddr(skb) = (skb)->nh.iph->daddr) |
| 52 | #define dnat_took_place(skb) (skb_origaddr(skb) != (skb)->nh.iph->daddr) | 52 | #define dnat_took_place(skb) (skb_origaddr(skb) != (skb)->nh.iph->daddr) |
| 53 | 53 | ||
| 54 | #define has_bridge_parent(device) ((device)->br_port != NULL) | ||
| 55 | #define bridge_parent(device) ((device)->br_port->br->dev) | ||
| 56 | |||
| 57 | #ifdef CONFIG_SYSCTL | 54 | #ifdef CONFIG_SYSCTL |
| 58 | static struct ctl_table_header *brnf_sysctl_header; | 55 | static struct ctl_table_header *brnf_sysctl_header; |
| 59 | static int brnf_call_iptables = 1; | 56 | static int brnf_call_iptables = 1; |
| @@ -98,6 +95,12 @@ static struct rtable __fake_rtable = { | |||
| 98 | .rt_flags = 0, | 95 | .rt_flags = 0, |
| 99 | }; | 96 | }; |
| 100 | 97 | ||
| 98 | static inline struct net_device *bridge_parent(const struct net_device *dev) | ||
| 99 | { | ||
| 100 | struct net_bridge_port *port = rcu_dereference(dev->br_port); | ||
| 101 | |||
| 102 | return port ? port->br->dev : NULL; | ||
| 103 | } | ||
| 101 | 104 | ||
| 102 | /* PF_BRIDGE/PRE_ROUTING *********************************************/ | 105 | /* PF_BRIDGE/PRE_ROUTING *********************************************/ |
| 103 | /* Undo the changes made for ip6tables PREROUTING and continue the | 106 | /* Undo the changes made for ip6tables PREROUTING and continue the |
| @@ -189,11 +192,15 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) | |||
| 189 | skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; | 192 | skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; |
| 190 | 193 | ||
| 191 | skb->dev = bridge_parent(skb->dev); | 194 | skb->dev = bridge_parent(skb->dev); |
| 192 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 195 | if (!skb->dev) |
| 193 | skb_pull(skb, VLAN_HLEN); | 196 | kfree_skb(skb); |
| 194 | skb->nh.raw += VLAN_HLEN; | 197 | else { |
| 198 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | ||
| 199 | skb_pull(skb, VLAN_HLEN); | ||
| 200 | skb->nh.raw += VLAN_HLEN; | ||
| 201 | } | ||
| 202 | skb->dst->output(skb); | ||
| 195 | } | 203 | } |
| 196 | skb->dst->output(skb); | ||
| 197 | return 0; | 204 | return 0; |
| 198 | } | 205 | } |
| 199 | 206 | ||
| @@ -270,7 +277,7 @@ bridged_dnat: | |||
| 270 | } | 277 | } |
| 271 | 278 | ||
| 272 | /* Some common code for IPv4/IPv6 */ | 279 | /* Some common code for IPv4/IPv6 */ |
| 273 | static void setup_pre_routing(struct sk_buff *skb) | 280 | static struct net_device *setup_pre_routing(struct sk_buff *skb) |
| 274 | { | 281 | { |
| 275 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; | 282 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; |
| 276 | 283 | ||
| @@ -282,6 +289,8 @@ static void setup_pre_routing(struct sk_buff *skb) | |||
| 282 | nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING; | 289 | nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING; |
| 283 | nf_bridge->physindev = skb->dev; | 290 | nf_bridge->physindev = skb->dev; |
| 284 | skb->dev = bridge_parent(skb->dev); | 291 | skb->dev = bridge_parent(skb->dev); |
| 292 | |||
| 293 | return skb->dev; | ||
| 285 | } | 294 | } |
| 286 | 295 | ||
| 287 | /* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */ | 296 | /* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */ |
| @@ -376,7 +385,8 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, | |||
| 376 | nf_bridge_put(skb->nf_bridge); | 385 | nf_bridge_put(skb->nf_bridge); |
| 377 | if ((nf_bridge = nf_bridge_alloc(skb)) == NULL) | 386 | if ((nf_bridge = nf_bridge_alloc(skb)) == NULL) |
| 378 | return NF_DROP; | 387 | return NF_DROP; |
| 379 | setup_pre_routing(skb); | 388 | if (!setup_pre_routing(skb)) |
| 389 | return NF_DROP; | ||
| 380 | 390 | ||
| 381 | NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, | 391 | NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, |
| 382 | br_nf_pre_routing_finish_ipv6); | 392 | br_nf_pre_routing_finish_ipv6); |
| @@ -465,7 +475,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
| 465 | nf_bridge_put(skb->nf_bridge); | 475 | nf_bridge_put(skb->nf_bridge); |
| 466 | if ((nf_bridge = nf_bridge_alloc(skb)) == NULL) | 476 | if ((nf_bridge = nf_bridge_alloc(skb)) == NULL) |
| 467 | return NF_DROP; | 477 | return NF_DROP; |
| 468 | setup_pre_routing(skb); | 478 | if (!setup_pre_routing(skb)) |
| 479 | return NF_DROP; | ||
| 469 | store_orig_dstaddr(skb); | 480 | store_orig_dstaddr(skb); |
| 470 | 481 | ||
| 471 | NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, | 482 | NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, |
| @@ -539,11 +550,16 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb, | |||
| 539 | struct sk_buff *skb = *pskb; | 550 | struct sk_buff *skb = *pskb; |
| 540 | struct nf_bridge_info *nf_bridge; | 551 | struct nf_bridge_info *nf_bridge; |
| 541 | struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); | 552 | struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); |
| 553 | struct net_device *parent; | ||
| 542 | int pf; | 554 | int pf; |
| 543 | 555 | ||
| 544 | if (!skb->nf_bridge) | 556 | if (!skb->nf_bridge) |
| 545 | return NF_ACCEPT; | 557 | return NF_ACCEPT; |
| 546 | 558 | ||
| 559 | parent = bridge_parent(out); | ||
| 560 | if (!parent) | ||
| 561 | return NF_DROP; | ||
| 562 | |||
| 547 | if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP) | 563 | if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP) |
| 548 | pf = PF_INET; | 564 | pf = PF_INET; |
| 549 | else | 565 | else |
| @@ -564,8 +580,8 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb, | |||
| 564 | nf_bridge->mask |= BRNF_BRIDGED; | 580 | nf_bridge->mask |= BRNF_BRIDGED; |
| 565 | nf_bridge->physoutdev = skb->dev; | 581 | nf_bridge->physoutdev = skb->dev; |
| 566 | 582 | ||
| 567 | NF_HOOK(pf, NF_IP_FORWARD, skb, bridge_parent(in), | 583 | NF_HOOK(pf, NF_IP_FORWARD, skb, bridge_parent(in), parent, |
| 568 | bridge_parent(out), br_nf_forward_finish); | 584 | br_nf_forward_finish); |
| 569 | 585 | ||
| 570 | return NF_STOLEN; | 586 | return NF_STOLEN; |
| 571 | } | 587 | } |
| @@ -688,6 +704,8 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, | |||
| 688 | goto out; | 704 | goto out; |
| 689 | } | 705 | } |
| 690 | realoutdev = bridge_parent(skb->dev); | 706 | realoutdev = bridge_parent(skb->dev); |
| 707 | if (!realoutdev) | ||
| 708 | return NF_DROP; | ||
| 691 | 709 | ||
| 692 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) | 710 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) |
| 693 | /* iptables should match -o br0.x */ | 711 | /* iptables should match -o br0.x */ |
| @@ -701,9 +719,11 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, | |||
| 701 | /* IP forwarded traffic has a physindev, locally | 719 | /* IP forwarded traffic has a physindev, locally |
| 702 | * generated traffic hasn't. */ | 720 | * generated traffic hasn't. */ |
| 703 | if (realindev != NULL) { | 721 | if (realindev != NULL) { |
| 704 | if (!(nf_bridge->mask & BRNF_DONT_TAKE_PARENT) && | 722 | if (!(nf_bridge->mask & BRNF_DONT_TAKE_PARENT) ) { |
| 705 | has_bridge_parent(realindev)) | 723 | struct net_device *parent = bridge_parent(realindev); |
| 706 | realindev = bridge_parent(realindev); | 724 | if (parent) |
| 725 | realindev = parent; | ||
| 726 | } | ||
| 707 | 727 | ||
| 708 | NF_HOOK_THRESH(pf, NF_IP_FORWARD, skb, realindev, | 728 | NF_HOOK_THRESH(pf, NF_IP_FORWARD, skb, realindev, |
| 709 | realoutdev, br_nf_local_out_finish, | 729 | realoutdev, br_nf_local_out_finish, |
| @@ -743,6 +763,9 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | |||
| 743 | if (!nf_bridge) | 763 | if (!nf_bridge) |
| 744 | return NF_ACCEPT; | 764 | return NF_ACCEPT; |
| 745 | 765 | ||
| 766 | if (!realoutdev) | ||
| 767 | return NF_DROP; | ||
| 768 | |||
| 746 | if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP) | 769 | if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP) |
| 747 | pf = PF_INET; | 770 | pf = PF_INET; |
| 748 | else | 771 | else |
