diff options
Diffstat (limited to 'net/ipv6/syncookies.c')
-rw-r--r-- | net/ipv6/syncookies.c | 75 |
1 files changed, 36 insertions, 39 deletions
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index bf63ac8a49b9..535a3ad262f1 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -24,26 +24,23 @@ | |||
24 | #define COOKIEBITS 24 /* Upper bits store count */ | 24 | #define COOKIEBITS 24 /* Upper bits store count */ |
25 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) | 25 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) |
26 | 26 | ||
27 | /* Table must be sorted. */ | 27 | static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS]; |
28 | |||
29 | /* RFC 2460, Section 8.3: | ||
30 | * [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..] | ||
31 | * | ||
32 | * Due to IPV6_MIN_MTU=1280 the lowest possible MSS is 1220, which allows | ||
33 | * using higher values than ipv4 tcp syncookies. | ||
34 | * The other values are chosen based on ethernet (1500 and 9k MTU), plus | ||
35 | * one that accounts for common encap (PPPoe) overhead. Table must be sorted. | ||
36 | */ | ||
28 | static __u16 const msstab[] = { | 37 | static __u16 const msstab[] = { |
29 | 64, | 38 | 1280 - 60, /* IPV6_MIN_MTU - 60 */ |
30 | 512, | ||
31 | 536, | ||
32 | 1280 - 60, | ||
33 | 1480 - 60, | 39 | 1480 - 60, |
34 | 1500 - 60, | 40 | 1500 - 60, |
35 | 4460 - 60, | ||
36 | 9000 - 60, | 41 | 9000 - 60, |
37 | }; | 42 | }; |
38 | 43 | ||
39 | /* | ||
40 | * This (misnamed) value is the age of syncookie which is permitted. | ||
41 | * Its ideal value should be dependent on TCP_TIMEOUT_INIT and | ||
42 | * sysctl_tcp_retries1. It's a rather complicated formula (exponential | ||
43 | * backoff) to compute at runtime so it's currently hardcoded here. | ||
44 | */ | ||
45 | #define COUNTER_TRIES 4 | ||
46 | |||
47 | static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, | 44 | static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, |
48 | struct request_sock *req, | 45 | struct request_sock *req, |
49 | struct dst_entry *dst) | 46 | struct dst_entry *dst) |
@@ -66,14 +63,18 @@ static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], | |||
66 | static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr, | 63 | static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr, |
67 | __be16 sport, __be16 dport, u32 count, int c) | 64 | __be16 sport, __be16 dport, u32 count, int c) |
68 | { | 65 | { |
69 | __u32 *tmp = __get_cpu_var(ipv6_cookie_scratch); | 66 | __u32 *tmp; |
67 | |||
68 | net_get_random_once(syncookie6_secret, sizeof(syncookie6_secret)); | ||
69 | |||
70 | tmp = __get_cpu_var(ipv6_cookie_scratch); | ||
70 | 71 | ||
71 | /* | 72 | /* |
72 | * we have 320 bits of information to hash, copy in the remaining | 73 | * we have 320 bits of information to hash, copy in the remaining |
73 | * 192 bits required for sha_transform, from the syncookie_secret | 74 | * 192 bits required for sha_transform, from the syncookie6_secret |
74 | * and overwrite the digest with the secret | 75 | * and overwrite the digest with the secret |
75 | */ | 76 | */ |
76 | memcpy(tmp + 10, syncookie_secret[c], 44); | 77 | memcpy(tmp + 10, syncookie6_secret[c], 44); |
77 | memcpy(tmp, saddr, 16); | 78 | memcpy(tmp, saddr, 16); |
78 | memcpy(tmp + 4, daddr, 16); | 79 | memcpy(tmp + 4, daddr, 16); |
79 | tmp[8] = ((__force u32)sport << 16) + (__force u32)dport; | 80 | tmp[8] = ((__force u32)sport << 16) + (__force u32)dport; |
@@ -86,8 +87,9 @@ static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *dadd | |||
86 | static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr, | 87 | static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr, |
87 | const struct in6_addr *daddr, | 88 | const struct in6_addr *daddr, |
88 | __be16 sport, __be16 dport, __u32 sseq, | 89 | __be16 sport, __be16 dport, __u32 sseq, |
89 | __u32 count, __u32 data) | 90 | __u32 data) |
90 | { | 91 | { |
92 | u32 count = tcp_cookie_time(); | ||
91 | return (cookie_hash(saddr, daddr, sport, dport, 0, 0) + | 93 | return (cookie_hash(saddr, daddr, sport, dport, 0, 0) + |
92 | sseq + (count << COOKIEBITS) + | 94 | sseq + (count << COOKIEBITS) + |
93 | ((cookie_hash(saddr, daddr, sport, dport, count, 1) + data) | 95 | ((cookie_hash(saddr, daddr, sport, dport, count, 1) + data) |
@@ -96,15 +98,14 @@ static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr, | |||
96 | 98 | ||
97 | static __u32 check_tcp_syn_cookie(__u32 cookie, const struct in6_addr *saddr, | 99 | static __u32 check_tcp_syn_cookie(__u32 cookie, const struct in6_addr *saddr, |
98 | const struct in6_addr *daddr, __be16 sport, | 100 | const struct in6_addr *daddr, __be16 sport, |
99 | __be16 dport, __u32 sseq, __u32 count, | 101 | __be16 dport, __u32 sseq) |
100 | __u32 maxdiff) | ||
101 | { | 102 | { |
102 | __u32 diff; | 103 | __u32 diff, count = tcp_cookie_time(); |
103 | 104 | ||
104 | cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq; | 105 | cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq; |
105 | 106 | ||
106 | diff = (count - (cookie >> COOKIEBITS)) & ((__u32) -1 >> COOKIEBITS); | 107 | diff = (count - (cookie >> COOKIEBITS)) & ((__u32) -1 >> COOKIEBITS); |
107 | if (diff >= maxdiff) | 108 | if (diff >= MAX_SYNCOOKIE_AGE) |
108 | return (__u32)-1; | 109 | return (__u32)-1; |
109 | 110 | ||
110 | return (cookie - | 111 | return (cookie - |
@@ -125,8 +126,7 @@ u32 __cookie_v6_init_sequence(const struct ipv6hdr *iph, | |||
125 | *mssp = msstab[mssind]; | 126 | *mssp = msstab[mssind]; |
126 | 127 | ||
127 | return secure_tcp_syn_cookie(&iph->saddr, &iph->daddr, th->source, | 128 | return secure_tcp_syn_cookie(&iph->saddr, &iph->daddr, th->source, |
128 | th->dest, ntohl(th->seq), | 129 | th->dest, ntohl(th->seq), mssind); |
129 | jiffies / (HZ * 60), mssind); | ||
130 | } | 130 | } |
131 | EXPORT_SYMBOL_GPL(__cookie_v6_init_sequence); | 131 | EXPORT_SYMBOL_GPL(__cookie_v6_init_sequence); |
132 | 132 | ||
@@ -146,8 +146,7 @@ int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th, | |||
146 | { | 146 | { |
147 | __u32 seq = ntohl(th->seq) - 1; | 147 | __u32 seq = ntohl(th->seq) - 1; |
148 | __u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr, | 148 | __u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr, |
149 | th->source, th->dest, seq, | 149 | th->source, th->dest, seq); |
150 | jiffies / (HZ * 60), COUNTER_TRIES); | ||
151 | 150 | ||
152 | return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0; | 151 | return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0; |
153 | } | 152 | } |
@@ -157,7 +156,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
157 | { | 156 | { |
158 | struct tcp_options_received tcp_opt; | 157 | struct tcp_options_received tcp_opt; |
159 | struct inet_request_sock *ireq; | 158 | struct inet_request_sock *ireq; |
160 | struct inet6_request_sock *ireq6; | ||
161 | struct tcp_request_sock *treq; | 159 | struct tcp_request_sock *treq; |
162 | struct ipv6_pinfo *np = inet6_sk(sk); | 160 | struct ipv6_pinfo *np = inet6_sk(sk); |
163 | struct tcp_sock *tp = tcp_sk(sk); | 161 | struct tcp_sock *tp = tcp_sk(sk); |
@@ -194,7 +192,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
194 | goto out; | 192 | goto out; |
195 | 193 | ||
196 | ireq = inet_rsk(req); | 194 | ireq = inet_rsk(req); |
197 | ireq6 = inet6_rsk(req); | ||
198 | treq = tcp_rsk(req); | 195 | treq = tcp_rsk(req); |
199 | treq->listener = NULL; | 196 | treq->listener = NULL; |
200 | 197 | ||
@@ -202,22 +199,22 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
202 | goto out_free; | 199 | goto out_free; |
203 | 200 | ||
204 | req->mss = mss; | 201 | req->mss = mss; |
205 | ireq->rmt_port = th->source; | 202 | ireq->ir_rmt_port = th->source; |
206 | ireq->loc_port = th->dest; | 203 | ireq->ir_num = ntohs(th->dest); |
207 | ireq6->rmt_addr = ipv6_hdr(skb)->saddr; | 204 | ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; |
208 | ireq6->loc_addr = ipv6_hdr(skb)->daddr; | 205 | ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; |
209 | if (ipv6_opt_accepted(sk, skb) || | 206 | if (ipv6_opt_accepted(sk, skb) || |
210 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 207 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
211 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 208 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { |
212 | atomic_inc(&skb->users); | 209 | atomic_inc(&skb->users); |
213 | ireq6->pktopts = skb; | 210 | ireq->pktopts = skb; |
214 | } | 211 | } |
215 | 212 | ||
216 | ireq6->iif = sk->sk_bound_dev_if; | 213 | ireq->ir_iif = sk->sk_bound_dev_if; |
217 | /* So that link locals have meaning */ | 214 | /* So that link locals have meaning */ |
218 | if (!sk->sk_bound_dev_if && | 215 | if (!sk->sk_bound_dev_if && |
219 | ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL) | 216 | ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) |
220 | ireq6->iif = inet6_iif(skb); | 217 | ireq->ir_iif = inet6_iif(skb); |
221 | 218 | ||
222 | req->expires = 0UL; | 219 | req->expires = 0UL; |
223 | req->num_retrans = 0; | 220 | req->num_retrans = 0; |
@@ -241,12 +238,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
241 | struct flowi6 fl6; | 238 | struct flowi6 fl6; |
242 | memset(&fl6, 0, sizeof(fl6)); | 239 | memset(&fl6, 0, sizeof(fl6)); |
243 | fl6.flowi6_proto = IPPROTO_TCP; | 240 | fl6.flowi6_proto = IPPROTO_TCP; |
244 | fl6.daddr = ireq6->rmt_addr; | 241 | fl6.daddr = ireq->ir_v6_rmt_addr; |
245 | final_p = fl6_update_dst(&fl6, np->opt, &final); | 242 | final_p = fl6_update_dst(&fl6, np->opt, &final); |
246 | fl6.saddr = ireq6->loc_addr; | 243 | fl6.saddr = ireq->ir_v6_loc_addr; |
247 | fl6.flowi6_oif = sk->sk_bound_dev_if; | 244 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
248 | fl6.flowi6_mark = sk->sk_mark; | 245 | fl6.flowi6_mark = sk->sk_mark; |
249 | fl6.fl6_dport = inet_rsk(req)->rmt_port; | 246 | fl6.fl6_dport = ireq->ir_rmt_port; |
250 | fl6.fl6_sport = inet_sk(sk)->inet_sport; | 247 | fl6.fl6_sport = inet_sk(sk)->inet_sport; |
251 | security_req_classify_flow(req, flowi6_to_flowi(&fl6)); | 248 | security_req_classify_flow(req, flowi6_to_flowi(&fl6)); |
252 | 249 | ||