diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 140 |
1 files changed, 85 insertions, 55 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 29adc668ad51..5400d75ff17a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -87,9 +87,8 @@ int sysctl_tcp_low_latency __read_mostly; | |||
| 87 | #ifdef CONFIG_TCP_MD5SIG | 87 | #ifdef CONFIG_TCP_MD5SIG |
| 88 | static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, | 88 | static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, |
| 89 | __be32 addr); | 89 | __be32 addr); |
| 90 | static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 90 | static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, |
| 91 | __be32 saddr, __be32 daddr, | 91 | __be32 daddr, __be32 saddr, struct tcphdr *th); |
| 92 | struct tcphdr *th, unsigned int tcplen); | ||
| 93 | #else | 92 | #else |
| 94 | static inline | 93 | static inline |
| 95 | struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) | 94 | struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) |
| @@ -583,11 +582,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) | |||
| 583 | arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; | 582 | arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; |
| 584 | rep.th.doff = arg.iov[0].iov_len / 4; | 583 | rep.th.doff = arg.iov[0].iov_len / 4; |
| 585 | 584 | ||
| 586 | tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[1], | 585 | tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[1], |
| 587 | key, | 586 | key, ip_hdr(skb)->daddr, |
| 588 | ip_hdr(skb)->daddr, | 587 | ip_hdr(skb)->saddr, &rep.th); |
| 589 | ip_hdr(skb)->saddr, | ||
| 590 | &rep.th, arg.iov[0].iov_len); | ||
| 591 | } | 588 | } |
| 592 | #endif | 589 | #endif |
| 593 | arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, | 590 | arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, |
| @@ -657,11 +654,9 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, | |||
| 657 | arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; | 654 | arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; |
| 658 | rep.th.doff = arg.iov[0].iov_len/4; | 655 | rep.th.doff = arg.iov[0].iov_len/4; |
| 659 | 656 | ||
| 660 | tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[offset], | 657 | tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[offset], |
| 661 | key, | 658 | key, ip_hdr(skb)->daddr, |
| 662 | ip_hdr(skb)->daddr, | 659 | ip_hdr(skb)->saddr, &rep.th); |
| 663 | ip_hdr(skb)->saddr, | ||
| 664 | &rep.th, arg.iov[0].iov_len); | ||
| 665 | } | 660 | } |
| 666 | #endif | 661 | #endif |
| 667 | arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, | 662 | arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, |
| @@ -989,28 +984,16 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, | |||
| 989 | newkey, cmd.tcpm_keylen); | 984 | newkey, cmd.tcpm_keylen); |
| 990 | } | 985 | } |
| 991 | 986 | ||
| 992 | static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 987 | static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, |
| 993 | __be32 saddr, __be32 daddr, | 988 | __be32 daddr, __be32 saddr, int nbytes) |
| 994 | struct tcphdr *th, | ||
| 995 | unsigned int tcplen) | ||
| 996 | { | 989 | { |
| 997 | struct tcp_md5sig_pool *hp; | ||
| 998 | struct tcp4_pseudohdr *bp; | 990 | struct tcp4_pseudohdr *bp; |
| 999 | int err; | 991 | struct scatterlist sg; |
| 1000 | |||
| 1001 | /* | ||
| 1002 | * Okay, so RFC2385 is turned on for this connection, | ||
| 1003 | * so we need to generate the MD5 hash for the packet now. | ||
| 1004 | */ | ||
| 1005 | |||
| 1006 | hp = tcp_get_md5sig_pool(); | ||
| 1007 | if (!hp) | ||
| 1008 | goto clear_hash_noput; | ||
| 1009 | 992 | ||
| 1010 | bp = &hp->md5_blk.ip4; | 993 | bp = &hp->md5_blk.ip4; |
| 1011 | 994 | ||
| 1012 | /* | 995 | /* |
| 1013 | * The TCP pseudo-header (in the order: source IP address, | 996 | * 1. the TCP pseudo-header (in the order: source IP address, |
| 1014 | * destination IP address, zero-padded protocol number, and | 997 | * destination IP address, zero-padded protocol number, and |
| 1015 | * segment length) | 998 | * segment length) |
| 1016 | */ | 999 | */ |
| @@ -1018,48 +1001,95 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | |||
| 1018 | bp->daddr = daddr; | 1001 | bp->daddr = daddr; |
| 1019 | bp->pad = 0; | 1002 | bp->pad = 0; |
| 1020 | bp->protocol = IPPROTO_TCP; | 1003 | bp->protocol = IPPROTO_TCP; |
| 1021 | bp->len = htons(tcplen); | 1004 | bp->len = cpu_to_be16(nbytes); |
| 1022 | 1005 | ||
| 1023 | err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), | 1006 | sg_init_one(&sg, bp, sizeof(*bp)); |
| 1024 | th, tcplen, hp); | 1007 | return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp)); |
| 1025 | if (err) | 1008 | } |
| 1009 | |||
| 1010 | static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, | ||
| 1011 | __be32 daddr, __be32 saddr, struct tcphdr *th) | ||
| 1012 | { | ||
| 1013 | struct tcp_md5sig_pool *hp; | ||
| 1014 | struct hash_desc *desc; | ||
| 1015 | |||
| 1016 | hp = tcp_get_md5sig_pool(); | ||
| 1017 | if (!hp) | ||
| 1018 | goto clear_hash_noput; | ||
| 1019 | desc = &hp->md5_desc; | ||
| 1020 | |||
| 1021 | if (crypto_hash_init(desc)) | ||
| 1022 | goto clear_hash; | ||
| 1023 | if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2)) | ||
| 1024 | goto clear_hash; | ||
| 1025 | if (tcp_md5_hash_header(hp, th)) | ||
| 1026 | goto clear_hash; | ||
| 1027 | if (tcp_md5_hash_key(hp, key)) | ||
| 1028 | goto clear_hash; | ||
| 1029 | if (crypto_hash_final(desc, md5_hash)) | ||
| 1026 | goto clear_hash; | 1030 | goto clear_hash; |
| 1027 | 1031 | ||
| 1028 | /* Free up the crypto pool */ | ||
| 1029 | tcp_put_md5sig_pool(); | 1032 | tcp_put_md5sig_pool(); |
| 1030 | out: | ||
| 1031 | return 0; | 1033 | return 0; |
| 1034 | |||
| 1032 | clear_hash: | 1035 | clear_hash: |
| 1033 | tcp_put_md5sig_pool(); | 1036 | tcp_put_md5sig_pool(); |
| 1034 | clear_hash_noput: | 1037 | clear_hash_noput: |
| 1035 | memset(md5_hash, 0, 16); | 1038 | memset(md5_hash, 0, 16); |
| 1036 | goto out; | 1039 | return 1; |
| 1037 | } | 1040 | } |
| 1038 | 1041 | ||
| 1039 | int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 1042 | int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, |
| 1040 | struct sock *sk, | 1043 | struct sock *sk, struct request_sock *req, |
| 1041 | struct dst_entry *dst, | 1044 | struct sk_buff *skb) |
| 1042 | struct request_sock *req, | ||
| 1043 | struct tcphdr *th, | ||
| 1044 | unsigned int tcplen) | ||
| 1045 | { | 1045 | { |
| 1046 | struct tcp_md5sig_pool *hp; | ||
| 1047 | struct hash_desc *desc; | ||
| 1048 | struct tcphdr *th = tcp_hdr(skb); | ||
| 1046 | __be32 saddr, daddr; | 1049 | __be32 saddr, daddr; |
| 1047 | 1050 | ||
| 1048 | if (sk) { | 1051 | if (sk) { |
| 1049 | saddr = inet_sk(sk)->saddr; | 1052 | saddr = inet_sk(sk)->saddr; |
| 1050 | daddr = inet_sk(sk)->daddr; | 1053 | daddr = inet_sk(sk)->daddr; |
| 1054 | } else if (req) { | ||
| 1055 | saddr = inet_rsk(req)->loc_addr; | ||
| 1056 | daddr = inet_rsk(req)->rmt_addr; | ||
| 1051 | } else { | 1057 | } else { |
| 1052 | struct rtable *rt = (struct rtable *)dst; | 1058 | const struct iphdr *iph = ip_hdr(skb); |
| 1053 | BUG_ON(!rt); | 1059 | saddr = iph->saddr; |
| 1054 | saddr = rt->rt_src; | 1060 | daddr = iph->daddr; |
| 1055 | daddr = rt->rt_dst; | ||
| 1056 | } | 1061 | } |
| 1057 | return tcp_v4_do_calc_md5_hash(md5_hash, key, | 1062 | |
| 1058 | saddr, daddr, | 1063 | hp = tcp_get_md5sig_pool(); |
| 1059 | th, tcplen); | 1064 | if (!hp) |
| 1065 | goto clear_hash_noput; | ||
| 1066 | desc = &hp->md5_desc; | ||
| 1067 | |||
| 1068 | if (crypto_hash_init(desc)) | ||
| 1069 | goto clear_hash; | ||
| 1070 | |||
| 1071 | if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, skb->len)) | ||
| 1072 | goto clear_hash; | ||
| 1073 | if (tcp_md5_hash_header(hp, th)) | ||
| 1074 | goto clear_hash; | ||
| 1075 | if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2)) | ||
| 1076 | goto clear_hash; | ||
| 1077 | if (tcp_md5_hash_key(hp, key)) | ||
| 1078 | goto clear_hash; | ||
| 1079 | if (crypto_hash_final(desc, md5_hash)) | ||
| 1080 | goto clear_hash; | ||
| 1081 | |||
| 1082 | tcp_put_md5sig_pool(); | ||
| 1083 | return 0; | ||
| 1084 | |||
| 1085 | clear_hash: | ||
| 1086 | tcp_put_md5sig_pool(); | ||
| 1087 | clear_hash_noput: | ||
| 1088 | memset(md5_hash, 0, 16); | ||
| 1089 | return 1; | ||
| 1060 | } | 1090 | } |
| 1061 | 1091 | ||
| 1062 | EXPORT_SYMBOL(tcp_v4_calc_md5_hash); | 1092 | EXPORT_SYMBOL(tcp_v4_md5_hash_skb); |
| 1063 | 1093 | ||
| 1064 | static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) | 1094 | static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) |
| 1065 | { | 1095 | { |
| @@ -1104,10 +1134,9 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) | |||
| 1104 | /* Okay, so this is hash_expected and hash_location - | 1134 | /* Okay, so this is hash_expected and hash_location - |
| 1105 | * so we need to calculate the checksum. | 1135 | * so we need to calculate the checksum. |
| 1106 | */ | 1136 | */ |
| 1107 | genhash = tcp_v4_do_calc_md5_hash(newhash, | 1137 | genhash = tcp_v4_md5_hash_skb(newhash, |
| 1108 | hash_expected, | 1138 | hash_expected, |
| 1109 | iph->saddr, iph->daddr, | 1139 | NULL, NULL, skb); |
| 1110 | th, skb->len); | ||
| 1111 | 1140 | ||
| 1112 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 1141 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
| 1113 | if (net_ratelimit()) { | 1142 | if (net_ratelimit()) { |
| @@ -1356,6 +1385,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1356 | if (newkey != NULL) | 1385 | if (newkey != NULL) |
| 1357 | tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, | 1386 | tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, |
| 1358 | newkey, key->keylen); | 1387 | newkey, key->keylen); |
| 1388 | newsk->sk_route_caps &= ~NETIF_F_GSO_MASK; | ||
| 1359 | } | 1389 | } |
| 1360 | #endif | 1390 | #endif |
| 1361 | 1391 | ||
| @@ -1719,7 +1749,7 @@ struct inet_connection_sock_af_ops ipv4_specific = { | |||
| 1719 | #ifdef CONFIG_TCP_MD5SIG | 1749 | #ifdef CONFIG_TCP_MD5SIG |
| 1720 | static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { | 1750 | static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { |
| 1721 | .md5_lookup = tcp_v4_md5_lookup, | 1751 | .md5_lookup = tcp_v4_md5_lookup, |
| 1722 | .calc_md5_hash = tcp_v4_calc_md5_hash, | 1752 | .calc_md5_hash = tcp_v4_md5_hash_skb, |
| 1723 | .md5_add = tcp_v4_md5_add_func, | 1753 | .md5_add = tcp_v4_md5_add_func, |
| 1724 | .md5_parse = tcp_v4_parse_md5_keys, | 1754 | .md5_parse = tcp_v4_parse_md5_keys, |
| 1725 | }; | 1755 | }; |
