diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/sit.c | 54 |
1 files changed, 41 insertions, 13 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 98fe53694a65..02f96dcbcf02 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -72,6 +72,8 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); | |||
72 | static int ipip6_tunnel_init(struct net_device *dev); | 72 | static int ipip6_tunnel_init(struct net_device *dev); |
73 | static void ipip6_tunnel_setup(struct net_device *dev); | 73 | static void ipip6_tunnel_setup(struct net_device *dev); |
74 | static void ipip6_dev_free(struct net_device *dev); | 74 | static void ipip6_dev_free(struct net_device *dev); |
75 | static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst, | ||
76 | __be32 *v4dst); | ||
75 | static struct rtnl_link_ops sit_link_ops __read_mostly; | 77 | static struct rtnl_link_ops sit_link_ops __read_mostly; |
76 | 78 | ||
77 | static int sit_net_id __read_mostly; | 79 | static int sit_net_id __read_mostly; |
@@ -590,6 +592,15 @@ out: | |||
590 | return err; | 592 | return err; |
591 | } | 593 | } |
592 | 594 | ||
595 | static inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr, | ||
596 | const struct in6_addr *v6addr) | ||
597 | { | ||
598 | __be32 v4embed = 0; | ||
599 | if (check_6rd(tunnel, v6addr, &v4embed) && v4addr != v4embed) | ||
600 | return true; | ||
601 | return false; | ||
602 | } | ||
603 | |||
593 | static int ipip6_rcv(struct sk_buff *skb) | 604 | static int ipip6_rcv(struct sk_buff *skb) |
594 | { | 605 | { |
595 | const struct iphdr *iph = ip_hdr(skb); | 606 | const struct iphdr *iph = ip_hdr(skb); |
@@ -608,10 +619,19 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
608 | skb->protocol = htons(ETH_P_IPV6); | 619 | skb->protocol = htons(ETH_P_IPV6); |
609 | skb->pkt_type = PACKET_HOST; | 620 | skb->pkt_type = PACKET_HOST; |
610 | 621 | ||
611 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && | 622 | if (tunnel->dev->priv_flags & IFF_ISATAP) { |
612 | !isatap_chksrc(skb, iph, tunnel)) { | 623 | if (!isatap_chksrc(skb, iph, tunnel)) { |
613 | tunnel->dev->stats.rx_errors++; | 624 | tunnel->dev->stats.rx_errors++; |
614 | goto out; | 625 | goto out; |
626 | } | ||
627 | } else { | ||
628 | if (is_spoofed_6rd(tunnel, iph->saddr, | ||
629 | &ipv6_hdr(skb)->saddr) || | ||
630 | is_spoofed_6rd(tunnel, iph->daddr, | ||
631 | &ipv6_hdr(skb)->daddr)) { | ||
632 | tunnel->dev->stats.rx_errors++; | ||
633 | goto out; | ||
634 | } | ||
615 | } | 635 | } |
616 | 636 | ||
617 | __skb_tunnel_rx(skb, tunnel->dev); | 637 | __skb_tunnel_rx(skb, tunnel->dev); |
@@ -645,14 +665,12 @@ out: | |||
645 | } | 665 | } |
646 | 666 | ||
647 | /* | 667 | /* |
648 | * Returns the embedded IPv4 address if the IPv6 address | 668 | * If the IPv6 address comes from 6rd / 6to4 (RFC 3056) addr space this function |
649 | * comes from 6rd / 6to4 (RFC 3056) addr space. | 669 | * stores the embedded IPv4 address in v4dst and returns true. |
650 | */ | 670 | */ |
651 | static inline | 671 | static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst, |
652 | __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel) | 672 | __be32 *v4dst) |
653 | { | 673 | { |
654 | __be32 dst = 0; | ||
655 | |||
656 | #ifdef CONFIG_IPV6_SIT_6RD | 674 | #ifdef CONFIG_IPV6_SIT_6RD |
657 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, | 675 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, |
658 | tunnel->ip6rd.prefixlen)) { | 676 | tunnel->ip6rd.prefixlen)) { |
@@ -671,14 +689,24 @@ __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel) | |||
671 | d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >> | 689 | d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >> |
672 | (32 - pbi1); | 690 | (32 - pbi1); |
673 | 691 | ||
674 | dst = tunnel->ip6rd.relay_prefix | htonl(d); | 692 | *v4dst = tunnel->ip6rd.relay_prefix | htonl(d); |
693 | return true; | ||
675 | } | 694 | } |
676 | #else | 695 | #else |
677 | if (v6dst->s6_addr16[0] == htons(0x2002)) { | 696 | if (v6dst->s6_addr16[0] == htons(0x2002)) { |
678 | /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ | 697 | /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ |
679 | memcpy(&dst, &v6dst->s6_addr16[1], 4); | 698 | memcpy(v4dst, &v6dst->s6_addr16[1], 4); |
699 | return true; | ||
680 | } | 700 | } |
681 | #endif | 701 | #endif |
702 | return false; | ||
703 | } | ||
704 | |||
705 | static inline __be32 try_6rd(struct ip_tunnel *tunnel, | ||
706 | const struct in6_addr *v6dst) | ||
707 | { | ||
708 | __be32 dst = 0; | ||
709 | check_6rd(tunnel, v6dst, &dst); | ||
682 | return dst; | 710 | return dst; |
683 | } | 711 | } |
684 | 712 | ||
@@ -739,7 +767,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
739 | } | 767 | } |
740 | 768 | ||
741 | if (!dst) | 769 | if (!dst) |
742 | dst = try_6rd(&iph6->daddr, tunnel); | 770 | dst = try_6rd(tunnel, &iph6->daddr); |
743 | 771 | ||
744 | if (!dst) { | 772 | if (!dst) { |
745 | struct neighbour *neigh = NULL; | 773 | struct neighbour *neigh = NULL; |