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 | }; |