diff options
| -rw-r--r-- | include/linux/netfilter_bridge.h | 5 | ||||
| -rw-r--r-- | include/net/neighbour.h | 14 | ||||
| -rw-r--r-- | net/bridge/br_netfilter.c | 90 |
3 files changed, 83 insertions, 26 deletions
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index ffab6c423a57..ea0e44b90432 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h | |||
| @@ -43,7 +43,8 @@ enum nf_br_hook_priorities { | |||
| 43 | #define BRNF_BRIDGED_DNAT 0x02 | 43 | #define BRNF_BRIDGED_DNAT 0x02 |
| 44 | #define BRNF_BRIDGED 0x04 | 44 | #define BRNF_BRIDGED 0x04 |
| 45 | #define BRNF_NF_BRIDGE_PREROUTING 0x08 | 45 | #define BRNF_NF_BRIDGE_PREROUTING 0x08 |
| 46 | 46 | #define BRNF_8021Q 0x10 | |
| 47 | #define BRNF_PPPoE 0x20 | ||
| 47 | 48 | ||
| 48 | /* Only used in br_forward.c */ | 49 | /* Only used in br_forward.c */ |
| 49 | extern int nf_bridge_copy_header(struct sk_buff *skb); | 50 | extern int nf_bridge_copy_header(struct sk_buff *skb); |
| @@ -75,6 +76,8 @@ static inline int br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb) | |||
| 75 | 76 | ||
| 76 | skb_pull(skb, ETH_HLEN); | 77 | skb_pull(skb, ETH_HLEN); |
| 77 | nf_bridge->mask ^= BRNF_BRIDGED_DNAT; | 78 | nf_bridge->mask ^= BRNF_BRIDGED_DNAT; |
| 79 | skb_copy_to_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), | ||
| 80 | skb->nf_bridge->data, ETH_HLEN-ETH_ALEN); | ||
| 78 | skb->dev = nf_bridge->physindev; | 81 | skb->dev = nf_bridge->physindev; |
| 79 | return br_handle_frame_finish(skb); | 82 | return br_handle_frame_finish(skb); |
| 80 | } | 83 | } |
diff --git a/include/net/neighbour.h b/include/net/neighbour.h index da1d58be31b7..eb21340a573b 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h | |||
| @@ -299,6 +299,20 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) | |||
| 299 | return 0; | 299 | return 0; |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
| 303 | static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) | ||
| 304 | { | ||
| 305 | unsigned seq, hh_alen; | ||
| 306 | |||
| 307 | do { | ||
| 308 | seq = read_seqbegin(&hh->hh_lock); | ||
| 309 | hh_alen = HH_DATA_ALIGN(ETH_HLEN); | ||
| 310 | memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN); | ||
| 311 | } while (read_seqretry(&hh->hh_lock, seq)); | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | #endif | ||
| 315 | |||
| 302 | static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb) | 316 | static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb) |
| 303 | { | 317 | { |
| 304 | unsigned seq; | 318 | unsigned seq; |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 05dc6304992c..b7e405dc9d1c 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
| @@ -196,15 +196,24 @@ static inline void nf_bridge_save_header(struct sk_buff *skb) | |||
| 196 | skb->nf_bridge->data, header_size); | 196 | skb->nf_bridge->data, header_size); |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | /* | 199 | static inline void nf_bridge_update_protocol(struct sk_buff *skb) |
| 200 | * When forwarding bridge frames, we save a copy of the original | 200 | { |
| 201 | * header before processing. | 201 | if (skb->nf_bridge->mask & BRNF_8021Q) |
| 202 | skb->protocol = htons(ETH_P_8021Q); | ||
| 203 | else if (skb->nf_bridge->mask & BRNF_PPPoE) | ||
| 204 | skb->protocol = htons(ETH_P_PPP_SES); | ||
| 205 | } | ||
| 206 | |||
| 207 | /* Fill in the header for fragmented IP packets handled by | ||
| 208 | * the IPv4 connection tracking code. | ||
| 202 | */ | 209 | */ |
| 203 | int nf_bridge_copy_header(struct sk_buff *skb) | 210 | int nf_bridge_copy_header(struct sk_buff *skb) |
| 204 | { | 211 | { |
| 205 | int err; | 212 | int err; |
| 206 | int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb); | 213 | unsigned int header_size; |
| 207 | 214 | ||
| 215 | nf_bridge_update_protocol(skb); | ||
| 216 | header_size = ETH_HLEN + nf_bridge_encap_header_len(skb); | ||
| 208 | err = skb_cow_head(skb, header_size); | 217 | err = skb_cow_head(skb, header_size); |
| 209 | if (err) | 218 | if (err) |
| 210 | return err; | 219 | return err; |
| @@ -238,6 +247,7 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) | |||
| 238 | skb_dst_set(skb, &rt->u.dst); | 247 | skb_dst_set(skb, &rt->u.dst); |
| 239 | 248 | ||
| 240 | skb->dev = nf_bridge->physindev; | 249 | skb->dev = nf_bridge->physindev; |
| 250 | nf_bridge_update_protocol(skb); | ||
| 241 | nf_bridge_push_encap_header(skb); | 251 | nf_bridge_push_encap_header(skb); |
| 242 | NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, | 252 | NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, |
| 243 | br_handle_frame_finish, 1); | 253 | br_handle_frame_finish, 1); |
| @@ -245,6 +255,38 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) | |||
| 245 | return 0; | 255 | return 0; |
| 246 | } | 256 | } |
| 247 | 257 | ||
| 258 | /* Obtain the correct destination MAC address, while preserving the original | ||
| 259 | * source MAC address. If we already know this address, we just copy it. If we | ||
| 260 | * don't, we use the neighbour framework to find out. In both cases, we make | ||
| 261 | * sure that br_handle_frame_finish() is called afterwards. | ||
| 262 | */ | ||
| 263 | static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) | ||
| 264 | { | ||
| 265 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; | ||
| 266 | struct dst_entry *dst; | ||
| 267 | |||
| 268 | skb->dev = bridge_parent(skb->dev); | ||
| 269 | if (!skb->dev) | ||
| 270 | goto free_skb; | ||
| 271 | dst = skb_dst(skb); | ||
| 272 | if (dst->hh) { | ||
| 273 | neigh_hh_bridge(dst->hh, skb); | ||
| 274 | skb->dev = nf_bridge->physindev; | ||
| 275 | return br_handle_frame_finish(skb); | ||
| 276 | } else if (dst->neighbour) { | ||
| 277 | /* the neighbour function below overwrites the complete | ||
| 278 | * MAC header, so we save the Ethernet source address and | ||
| 279 | * protocol number. */ | ||
| 280 | skb_copy_from_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN); | ||
| 281 | /* tell br_dev_xmit to continue with forwarding */ | ||
| 282 | nf_bridge->mask |= BRNF_BRIDGED_DNAT; | ||
| 283 | return dst->neighbour->output(skb); | ||
| 284 | } | ||
| 285 | free_skb: | ||
| 286 | kfree_skb(skb); | ||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 248 | /* This requires some explaining. If DNAT has taken place, | 290 | /* This requires some explaining. If DNAT has taken place, |
| 249 | * we will need to fix up the destination Ethernet address. | 291 | * we will need to fix up the destination Ethernet address. |
| 250 | * | 292 | * |
| @@ -283,25 +325,6 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) | |||
| 283 | * device, we proceed as if ip_route_input() succeeded. If it differs from the | 325 | * device, we proceed as if ip_route_input() succeeded. If it differs from the |
| 284 | * logical bridge port or if ip_route_output_key() fails we drop the packet. | 326 | * logical bridge port or if ip_route_output_key() fails we drop the packet. |
| 285 | */ | 327 | */ |
| 286 | |||
| 287 | static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) | ||
| 288 | { | ||
| 289 | skb->dev = bridge_parent(skb->dev); | ||
| 290 | if (skb->dev) { | ||
| 291 | struct dst_entry *dst = skb_dst(skb); | ||
| 292 | |||
| 293 | nf_bridge_pull_encap_header(skb); | ||
| 294 | skb->nf_bridge->mask |= BRNF_BRIDGED_DNAT; | ||
| 295 | |||
| 296 | if (dst->hh) | ||
| 297 | return neigh_hh_output(dst->hh, skb); | ||
| 298 | else if (dst->neighbour) | ||
| 299 | return dst->neighbour->output(skb); | ||
| 300 | } | ||
| 301 | kfree_skb(skb); | ||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | |||
| 305 | static int br_nf_pre_routing_finish(struct sk_buff *skb) | 328 | static int br_nf_pre_routing_finish(struct sk_buff *skb) |
| 306 | { | 329 | { |
| 307 | struct net_device *dev = skb->dev; | 330 | struct net_device *dev = skb->dev; |
| @@ -354,6 +377,7 @@ free_skb: | |||
| 354 | if (skb_dst(skb)->dev == dev) { | 377 | if (skb_dst(skb)->dev == dev) { |
| 355 | bridged_dnat: | 378 | bridged_dnat: |
| 356 | skb->dev = nf_bridge->physindev; | 379 | skb->dev = nf_bridge->physindev; |
| 380 | nf_bridge_update_protocol(skb); | ||
| 357 | nf_bridge_push_encap_header(skb); | 381 | nf_bridge_push_encap_header(skb); |
| 358 | NF_HOOK_THRESH(NFPROTO_BRIDGE, | 382 | NF_HOOK_THRESH(NFPROTO_BRIDGE, |
| 359 | NF_BR_PRE_ROUTING, | 383 | NF_BR_PRE_ROUTING, |
| @@ -376,6 +400,7 @@ bridged_dnat: | |||
| 376 | } | 400 | } |
| 377 | 401 | ||
| 378 | skb->dev = nf_bridge->physindev; | 402 | skb->dev = nf_bridge->physindev; |
| 403 | nf_bridge_update_protocol(skb); | ||
| 379 | nf_bridge_push_encap_header(skb); | 404 | nf_bridge_push_encap_header(skb); |
| 380 | NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, | 405 | NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, |
| 381 | br_handle_frame_finish, 1); | 406 | br_handle_frame_finish, 1); |
| @@ -396,6 +421,10 @@ static struct net_device *setup_pre_routing(struct sk_buff *skb) | |||
| 396 | nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING; | 421 | nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING; |
| 397 | nf_bridge->physindev = skb->dev; | 422 | nf_bridge->physindev = skb->dev; |
| 398 | skb->dev = bridge_parent(skb->dev); | 423 | skb->dev = bridge_parent(skb->dev); |
| 424 | if (skb->protocol == htons(ETH_P_8021Q)) | ||
| 425 | nf_bridge->mask |= BRNF_8021Q; | ||
| 426 | else if (skb->protocol == htons(ETH_P_PPP_SES)) | ||
| 427 | nf_bridge->mask |= BRNF_PPPoE; | ||
| 399 | 428 | ||
| 400 | return skb->dev; | 429 | return skb->dev; |
| 401 | } | 430 | } |
| @@ -494,6 +523,7 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, | |||
| 494 | if (!setup_pre_routing(skb)) | 523 | if (!setup_pre_routing(skb)) |
| 495 | return NF_DROP; | 524 | return NF_DROP; |
| 496 | 525 | ||
| 526 | skb->protocol = htons(ETH_P_IPV6); | ||
| 497 | NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, | 527 | NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, |
| 498 | br_nf_pre_routing_finish_ipv6); | 528 | br_nf_pre_routing_finish_ipv6); |
| 499 | 529 | ||
| @@ -566,6 +596,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
| 566 | if (!setup_pre_routing(skb)) | 596 | if (!setup_pre_routing(skb)) |
| 567 | return NF_DROP; | 597 | return NF_DROP; |
| 568 | store_orig_dstaddr(skb); | 598 | store_orig_dstaddr(skb); |
| 599 | skb->protocol = htons(ETH_P_IP); | ||
| 569 | 600 | ||
| 570 | NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, | 601 | NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, |
| 571 | br_nf_pre_routing_finish); | 602 | br_nf_pre_routing_finish); |
| @@ -614,7 +645,9 @@ static int br_nf_forward_finish(struct sk_buff *skb) | |||
| 614 | } else { | 645 | } else { |
| 615 | in = *((struct net_device **)(skb->cb)); | 646 | in = *((struct net_device **)(skb->cb)); |
| 616 | } | 647 | } |
| 648 | nf_bridge_update_protocol(skb); | ||
| 617 | nf_bridge_push_encap_header(skb); | 649 | nf_bridge_push_encap_header(skb); |
| 650 | |||
| 618 | NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, in, | 651 | NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, in, |
| 619 | skb->dev, br_forward_finish, 1); | 652 | skb->dev, br_forward_finish, 1); |
| 620 | return 0; | 653 | return 0; |
| @@ -666,6 +699,10 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb, | |||
| 666 | /* The physdev module checks on this */ | 699 | /* The physdev module checks on this */ |
| 667 | nf_bridge->mask |= BRNF_BRIDGED; | 700 | nf_bridge->mask |= BRNF_BRIDGED; |
| 668 | nf_bridge->physoutdev = skb->dev; | 701 | nf_bridge->physoutdev = skb->dev; |
| 702 | if (pf == PF_INET) | ||
| 703 | skb->protocol = htons(ETH_P_IP); | ||
| 704 | else | ||
| 705 | skb->protocol = htons(ETH_P_IPV6); | ||
| 669 | 706 | ||
| 670 | NF_HOOK(pf, NF_INET_FORWARD, skb, bridge_parent(in), parent, | 707 | NF_HOOK(pf, NF_INET_FORWARD, skb, bridge_parent(in), parent, |
| 671 | br_nf_forward_finish); | 708 | br_nf_forward_finish); |
| @@ -706,8 +743,7 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb, | |||
| 706 | #if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE) | 743 | #if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE) |
| 707 | static int br_nf_dev_queue_xmit(struct sk_buff *skb) | 744 | static int br_nf_dev_queue_xmit(struct sk_buff *skb) |
| 708 | { | 745 | { |
| 709 | if (skb->nfct != NULL && | 746 | if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) && |
| 710 | (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb)) && | ||
| 711 | skb->len > skb->dev->mtu && | 747 | skb->len > skb->dev->mtu && |
| 712 | !skb_is_gso(skb)) | 748 | !skb_is_gso(skb)) |
| 713 | return ip_fragment(skb, br_dev_queue_push_xmit); | 749 | return ip_fragment(skb, br_dev_queue_push_xmit); |
| @@ -755,6 +791,10 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb, | |||
| 755 | 791 | ||
| 756 | nf_bridge_pull_encap_header(skb); | 792 | nf_bridge_pull_encap_header(skb); |
| 757 | nf_bridge_save_header(skb); | 793 | nf_bridge_save_header(skb); |
| 794 | if (pf == PF_INET) | ||
| 795 | skb->protocol = htons(ETH_P_IP); | ||
| 796 | else | ||
| 797 | skb->protocol = htons(ETH_P_IPV6); | ||
| 758 | 798 | ||
| 759 | NF_HOOK(pf, NF_INET_POST_ROUTING, skb, NULL, realoutdev, | 799 | NF_HOOK(pf, NF_INET_POST_ROUTING, skb, NULL, realoutdev, |
| 760 | br_nf_dev_queue_xmit); | 800 | br_nf_dev_queue_xmit); |
