diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 127 |
1 files changed, 83 insertions, 44 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index ca5b93a5c02a..ae45f9835014 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -736,64 +736,105 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, | |||
736 | return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); | 736 | return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); |
737 | } | 737 | } |
738 | 738 | ||
739 | static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 739 | static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, |
740 | struct in6_addr *saddr, | 740 | struct in6_addr *daddr, |
741 | struct in6_addr *daddr, | 741 | struct in6_addr *saddr, int nbytes) |
742 | struct tcphdr *th, unsigned int tcplen) | ||
743 | { | 742 | { |
744 | struct tcp_md5sig_pool *hp; | ||
745 | struct tcp6_pseudohdr *bp; | 743 | struct tcp6_pseudohdr *bp; |
746 | int err; | 744 | struct scatterlist sg; |
747 | |||
748 | hp = tcp_get_md5sig_pool(); | ||
749 | if (!hp) { | ||
750 | printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); | ||
751 | goto clear_hash_noput; | ||
752 | } | ||
753 | 745 | ||
754 | bp = &hp->md5_blk.ip6; | 746 | bp = &hp->md5_blk.ip6; |
755 | |||
756 | /* 1. TCP pseudo-header (RFC2460) */ | 747 | /* 1. TCP pseudo-header (RFC2460) */ |
757 | ipv6_addr_copy(&bp->saddr, saddr); | 748 | ipv6_addr_copy(&bp->saddr, saddr); |
758 | ipv6_addr_copy(&bp->daddr, daddr); | 749 | ipv6_addr_copy(&bp->daddr, daddr); |
759 | bp->len = htonl(tcplen); | 750 | bp->protocol = cpu_to_be32(IPPROTO_TCP); |
760 | bp->protocol = htonl(IPPROTO_TCP); | 751 | bp->len = cpu_to_be16(nbytes); |
761 | 752 | ||
762 | err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), | 753 | sg_init_one(&sg, bp, sizeof(*bp)); |
763 | th, tcplen, hp); | 754 | return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp)); |
755 | } | ||
764 | 756 | ||
765 | if (err) | 757 | static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, |
758 | struct in6_addr *daddr, struct in6_addr *saddr, | ||
759 | struct tcphdr *th) | ||
760 | { | ||
761 | struct tcp_md5sig_pool *hp; | ||
762 | struct hash_desc *desc; | ||
763 | |||
764 | hp = tcp_get_md5sig_pool(); | ||
765 | if (!hp) | ||
766 | goto clear_hash_noput; | ||
767 | desc = &hp->md5_desc; | ||
768 | |||
769 | if (crypto_hash_init(desc)) | ||
770 | goto clear_hash; | ||
771 | if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2)) | ||
772 | goto clear_hash; | ||
773 | if (tcp_md5_hash_header(hp, th)) | ||
774 | goto clear_hash; | ||
775 | if (tcp_md5_hash_key(hp, key)) | ||
776 | goto clear_hash; | ||
777 | if (crypto_hash_final(desc, md5_hash)) | ||
766 | goto clear_hash; | 778 | goto clear_hash; |
767 | 779 | ||
768 | /* Free up the crypto pool */ | ||
769 | tcp_put_md5sig_pool(); | 780 | tcp_put_md5sig_pool(); |
770 | out: | ||
771 | return 0; | 781 | return 0; |
782 | |||
772 | clear_hash: | 783 | clear_hash: |
773 | tcp_put_md5sig_pool(); | 784 | tcp_put_md5sig_pool(); |
774 | clear_hash_noput: | 785 | clear_hash_noput: |
775 | memset(md5_hash, 0, 16); | 786 | memset(md5_hash, 0, 16); |
776 | goto out; | 787 | return 1; |
777 | } | 788 | } |
778 | 789 | ||
779 | static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 790 | static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, |
780 | struct sock *sk, | 791 | struct sock *sk, struct request_sock *req, |
781 | struct dst_entry *dst, | 792 | struct sk_buff *skb) |
782 | struct request_sock *req, | ||
783 | struct tcphdr *th, unsigned int tcplen) | ||
784 | { | 793 | { |
785 | struct in6_addr *saddr, *daddr; | 794 | struct in6_addr *saddr, *daddr; |
795 | struct tcp_md5sig_pool *hp; | ||
796 | struct hash_desc *desc; | ||
797 | struct tcphdr *th = tcp_hdr(skb); | ||
786 | 798 | ||
787 | if (sk) { | 799 | if (sk) { |
788 | saddr = &inet6_sk(sk)->saddr; | 800 | saddr = &inet6_sk(sk)->saddr; |
789 | daddr = &inet6_sk(sk)->daddr; | 801 | daddr = &inet6_sk(sk)->daddr; |
790 | } else { | 802 | } else if (req) { |
791 | saddr = &inet6_rsk(req)->loc_addr; | 803 | saddr = &inet6_rsk(req)->loc_addr; |
792 | daddr = &inet6_rsk(req)->rmt_addr; | 804 | daddr = &inet6_rsk(req)->rmt_addr; |
805 | } else { | ||
806 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | ||
807 | saddr = &ip6h->saddr; | ||
808 | daddr = &ip6h->daddr; | ||
793 | } | 809 | } |
794 | return tcp_v6_do_calc_md5_hash(md5_hash, key, | 810 | |
795 | saddr, daddr, | 811 | hp = tcp_get_md5sig_pool(); |
796 | th, tcplen); | 812 | if (!hp) |
813 | goto clear_hash_noput; | ||
814 | desc = &hp->md5_desc; | ||
815 | |||
816 | if (crypto_hash_init(desc)) | ||
817 | goto clear_hash; | ||
818 | |||
819 | if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len)) | ||
820 | goto clear_hash; | ||
821 | if (tcp_md5_hash_header(hp, th)) | ||
822 | goto clear_hash; | ||
823 | if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2)) | ||
824 | goto clear_hash; | ||
825 | if (tcp_md5_hash_key(hp, key)) | ||
826 | goto clear_hash; | ||
827 | if (crypto_hash_final(desc, md5_hash)) | ||
828 | goto clear_hash; | ||
829 | |||
830 | tcp_put_md5sig_pool(); | ||
831 | return 0; | ||
832 | |||
833 | clear_hash: | ||
834 | tcp_put_md5sig_pool(); | ||
835 | clear_hash_noput: | ||
836 | memset(md5_hash, 0, 16); | ||
837 | return 1; | ||
797 | } | 838 | } |
798 | 839 | ||
799 | static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | 840 | static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) |
@@ -834,10 +875,10 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
834 | } | 875 | } |
835 | 876 | ||
836 | /* check the signature */ | 877 | /* check the signature */ |
837 | genhash = tcp_v6_do_calc_md5_hash(newhash, | 878 | genhash = tcp_v6_md5_hash_skb(newhash, |
838 | hash_expected, | 879 | hash_expected, |
839 | &ip6h->saddr, &ip6h->daddr, | 880 | NULL, NULL, skb); |
840 | th, skb->len); | 881 | |
841 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 882 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
842 | if (net_ratelimit()) { | 883 | if (net_ratelimit()) { |
843 | printk(KERN_INFO "MD5 Hash %s for " | 884 | printk(KERN_INFO "MD5 Hash %s for " |
@@ -974,10 +1015,9 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
974 | (TCPOPT_NOP << 16) | | 1015 | (TCPOPT_NOP << 16) | |
975 | (TCPOPT_MD5SIG << 8) | | 1016 | (TCPOPT_MD5SIG << 8) | |
976 | TCPOLEN_MD5SIG); | 1017 | TCPOLEN_MD5SIG); |
977 | tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, | 1018 | tcp_v6_md5_hash_hdr((__u8 *)&opt[1], key, |
978 | &ipv6_hdr(skb)->daddr, | 1019 | &ipv6_hdr(skb)->daddr, |
979 | &ipv6_hdr(skb)->saddr, | 1020 | &ipv6_hdr(skb)->saddr, t1); |
980 | t1, tot_len); | ||
981 | } | 1021 | } |
982 | #endif | 1022 | #endif |
983 | 1023 | ||
@@ -1064,10 +1104,9 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 | |||
1064 | if (key) { | 1104 | if (key) { |
1065 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | | 1105 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | |
1066 | (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); | 1106 | (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); |
1067 | tcp_v6_do_calc_md5_hash((__u8 *)topt, key, | 1107 | tcp_v6_md5_hash_hdr((__u8 *)topt, key, |
1068 | &ipv6_hdr(skb)->daddr, | 1108 | &ipv6_hdr(skb)->daddr, |
1069 | &ipv6_hdr(skb)->saddr, | 1109 | &ipv6_hdr(skb)->saddr, t1); |
1070 | t1, tot_len); | ||
1071 | } | 1110 | } |
1072 | #endif | 1111 | #endif |
1073 | 1112 | ||
@@ -1783,7 +1822,7 @@ static struct inet_connection_sock_af_ops ipv6_specific = { | |||
1783 | #ifdef CONFIG_TCP_MD5SIG | 1822 | #ifdef CONFIG_TCP_MD5SIG |
1784 | static struct tcp_sock_af_ops tcp_sock_ipv6_specific = { | 1823 | static struct tcp_sock_af_ops tcp_sock_ipv6_specific = { |
1785 | .md5_lookup = tcp_v6_md5_lookup, | 1824 | .md5_lookup = tcp_v6_md5_lookup, |
1786 | .calc_md5_hash = tcp_v6_calc_md5_hash, | 1825 | .calc_md5_hash = tcp_v6_md5_hash_skb, |
1787 | .md5_add = tcp_v6_md5_add_func, | 1826 | .md5_add = tcp_v6_md5_add_func, |
1788 | .md5_parse = tcp_v6_parse_md5_keys, | 1827 | .md5_parse = tcp_v6_parse_md5_keys, |
1789 | }; | 1828 | }; |
@@ -1815,7 +1854,7 @@ static struct inet_connection_sock_af_ops ipv6_mapped = { | |||
1815 | #ifdef CONFIG_TCP_MD5SIG | 1854 | #ifdef CONFIG_TCP_MD5SIG |
1816 | static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { | 1855 | static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { |
1817 | .md5_lookup = tcp_v4_md5_lookup, | 1856 | .md5_lookup = tcp_v4_md5_lookup, |
1818 | .calc_md5_hash = tcp_v4_calc_md5_hash, | 1857 | .calc_md5_hash = tcp_v4_md5_hash_skb, |
1819 | .md5_add = tcp_v6_md5_add_func, | 1858 | .md5_add = tcp_v6_md5_add_func, |
1820 | .md5_parse = tcp_v6_parse_md5_keys, | 1859 | .md5_parse = tcp_v6_parse_md5_keys, |
1821 | }; | 1860 | }; |