diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -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 | }; |
