aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/sit.c
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2013-01-29 03:24:25 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-29 15:22:03 -0500
commit218774dc341f219bfcf940304a081b121a0e8099 (patch)
tree3dda133e7c1d25847198fc85108535f0b912a2ed /net/ipv6/sit.c
parentee873fda3bec7c668407b837fc5519eb961fcd37 (diff)
ipv6: add anti-spoofing checks for 6to4 and 6rd
This patch adds anti-spoofing checks in sit.c as specified in RFC3964 section 5.2 for 6to4 and RFC5969 section 12 for 6rd. I left out the checks which could easily be implemented with netfilter. Specifically this patch adds following logic (based loosely on the pseudocode in RFC3964 section 5.2): if prefix (inner_src_v6) == rd6_prefix (2002::/16 is the default) and outer_src_v4 != embedded_ipv4 (inner_src_v6) drop if prefix (inner_dst_v6) == rd6_prefix (or 2002::/16 is the default) and outer_dst_v4 != embedded_ipv4 (inner_dst_v6) drop accept To accomplish the specified security checks proposed by above RFCs, it is still necessary to employ uRPF filters with netfilter. These new checks only kick in if the employed addresses are within the 2002::/16 or another range specified by the 6rd-prefix (which defaults to 2002::/16). Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Cc: David Miller <davem@davemloft.net> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r--net/ipv6/sit.c54
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");
72static int ipip6_tunnel_init(struct net_device *dev); 72static int ipip6_tunnel_init(struct net_device *dev);
73static void ipip6_tunnel_setup(struct net_device *dev); 73static void ipip6_tunnel_setup(struct net_device *dev);
74static void ipip6_dev_free(struct net_device *dev); 74static void ipip6_dev_free(struct net_device *dev);
75static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst,
76 __be32 *v4dst);
75static struct rtnl_link_ops sit_link_ops __read_mostly; 77static struct rtnl_link_ops sit_link_ops __read_mostly;
76 78
77static int sit_net_id __read_mostly; 79static int sit_net_id __read_mostly;
@@ -590,6 +592,15 @@ out:
590 return err; 592 return err;
591} 593}
592 594
595static 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
593static int ipip6_rcv(struct sk_buff *skb) 604static 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 */
651static inline 671static 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
705static 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;