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); |