aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorBart De Schuymer <bdschuym@pandora.be>2010-04-15 06:26:39 -0400
committerPatrick McHardy <kaber@trash.net>2010-04-15 06:26:39 -0400
commite179e6322ac334e21a3c6d669d95bc967e5d0a80 (patch)
treeeee21d4e85ffeed02c6a25a8b224845cb9ed0fd2 /net
parentea2d9b41bd418894d1ee25de1642c3325d71c397 (diff)
netfilter: bridge-netfilter: Fix MAC header handling with IP DNAT
- fix IP DNAT on vlan- or pppoe-encapsulated traffic: The functions neigh_hh_output() or dst->neighbour->output() overwrite the complete Ethernet header, although we only need the destination MAC address. For encapsulated packets, they ended up overwriting the encapsulating header. The new code copies the Ethernet source MAC address and protocol number before calling dst->neighbour->output(). The Ethernet source MAC and protocol number are copied back in place in br_nf_pre_routing_finish_bridge_slow(). This also makes the IP DNAT more transparent because in the old scheme the source MAC of the bridge was copied into the source address in the Ethernet header. We also let skb->protocol equal ETH_P_IP resp. ETH_P_IPV6 during the execution of the PF_INET resp. PF_INET6 hooks. - Speed up IP DNAT by calling neigh_hh_bridge() instead of neigh_hh_output(): if dst->hh is available, we already know the MAC address so we can just copy it. Signed-off-by: Bart De Schuymer <bdschuym@pandora.be> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_netfilter.c90
1 files changed, 65 insertions, 25 deletions
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/* 199static 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 */
203int nf_bridge_copy_header(struct sk_buff *skb) 210int 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 */
263static 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 }
285free_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
287static 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
305static int br_nf_pre_routing_finish(struct sk_buff *skb) 328static 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) {
355bridged_dnat: 378bridged_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)
707static int br_nf_dev_queue_xmit(struct sk_buff *skb) 744static 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);