diff options
author | William Allen Simpson <william.allen.simpson@gmail.com> | 2009-12-02 13:25:27 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-03 01:07:26 -0500 |
commit | 4957faade11b3a278c3b3cade3411ddc20afa791 (patch) | |
tree | 57f994bab69353baf5f554b89cf9107c3372ecce /net | |
parent | bd0388ae77075026d6a9f9eb6026dfd1d52ce0e9 (diff) |
TCPCT part 1g: Responder Cookie => Initiator
Parse incoming TCP_COOKIE option(s).
Calculate <SYN,ACK> TCP_COOKIE option.
Send optional <SYN,ACK> data.
This is a significantly revised implementation of an earlier (year-old)
patch that no longer applies cleanly, with permission of the original
author (Adam Langley):
http://thread.gmane.org/gmane.linux.network/102586
Requires:
TCPCT part 1a: add request_values parameter for sending SYNACK
TCPCT part 1b: generate Responder Cookie secret
TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS
TCPCT part 1d: define TCP cookie option, extend existing struct's
TCPCT part 1e: implement socket option TCP_COOKIE_TRANSACTIONS
TCPCT part 1f: Initiator Cookie => Responder
Signed-off-by: William.Allen.Simpson@gmail.com
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/syncookies.c | 5 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 75 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 47 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 14 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 103 | ||||
-rw-r--r-- | net/ipv6/syncookies.c | 5 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 52 |
7 files changed, 258 insertions, 43 deletions
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 3146cc401748..26399ad2a289 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c | |||
@@ -253,6 +253,8 @@ EXPORT_SYMBOL(cookie_check_timestamp); | |||
253 | struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | 253 | struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, |
254 | struct ip_options *opt) | 254 | struct ip_options *opt) |
255 | { | 255 | { |
256 | struct tcp_options_received tcp_opt; | ||
257 | u8 *hash_location; | ||
256 | struct inet_request_sock *ireq; | 258 | struct inet_request_sock *ireq; |
257 | struct tcp_request_sock *treq; | 259 | struct tcp_request_sock *treq; |
258 | struct tcp_sock *tp = tcp_sk(sk); | 260 | struct tcp_sock *tp = tcp_sk(sk); |
@@ -263,7 +265,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
263 | int mss; | 265 | int mss; |
264 | struct rtable *rt; | 266 | struct rtable *rt; |
265 | __u8 rcv_wscale; | 267 | __u8 rcv_wscale; |
266 | struct tcp_options_received tcp_opt; | ||
267 | 268 | ||
268 | if (!sysctl_tcp_syncookies || !th->ack) | 269 | if (!sysctl_tcp_syncookies || !th->ack) |
269 | goto out; | 270 | goto out; |
@@ -341,7 +342,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
341 | 342 | ||
342 | /* check for timestamp cookie support */ | 343 | /* check for timestamp cookie support */ |
343 | memset(&tcp_opt, 0, sizeof(tcp_opt)); | 344 | memset(&tcp_opt, 0, sizeof(tcp_opt)); |
344 | tcp_parse_options(skb, &tcp_opt, 0, &rt->u.dst); | 345 | tcp_parse_options(skb, &tcp_opt, &hash_location, 0, &rt->u.dst); |
345 | 346 | ||
346 | if (tcp_opt.saw_tstamp) | 347 | if (tcp_opt.saw_tstamp) |
347 | cookie_check_timestamp(&tcp_opt); | 348 | cookie_check_timestamp(&tcp_opt); |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index be166e0e11c5..57ae96a04220 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -3698,7 +3698,7 @@ old_ack: | |||
3698 | * the fast version below fails. | 3698 | * the fast version below fails. |
3699 | */ | 3699 | */ |
3700 | void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, | 3700 | void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, |
3701 | int estab, struct dst_entry *dst) | 3701 | u8 **hvpp, int estab, struct dst_entry *dst) |
3702 | { | 3702 | { |
3703 | unsigned char *ptr; | 3703 | unsigned char *ptr; |
3704 | struct tcphdr *th = tcp_hdr(skb); | 3704 | struct tcphdr *th = tcp_hdr(skb); |
@@ -3785,7 +3785,30 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, | |||
3785 | */ | 3785 | */ |
3786 | break; | 3786 | break; |
3787 | #endif | 3787 | #endif |
3788 | } | 3788 | case TCPOPT_COOKIE: |
3789 | /* This option is variable length. | ||
3790 | */ | ||
3791 | switch (opsize) { | ||
3792 | case TCPOLEN_COOKIE_BASE: | ||
3793 | /* not yet implemented */ | ||
3794 | break; | ||
3795 | case TCPOLEN_COOKIE_PAIR: | ||
3796 | /* not yet implemented */ | ||
3797 | break; | ||
3798 | case TCPOLEN_COOKIE_MIN+0: | ||
3799 | case TCPOLEN_COOKIE_MIN+2: | ||
3800 | case TCPOLEN_COOKIE_MIN+4: | ||
3801 | case TCPOLEN_COOKIE_MIN+6: | ||
3802 | case TCPOLEN_COOKIE_MAX: | ||
3803 | /* 16-bit multiple */ | ||
3804 | opt_rx->cookie_plus = opsize; | ||
3805 | *hvpp = ptr; | ||
3806 | default: | ||
3807 | /* ignore option */ | ||
3808 | break; | ||
3809 | }; | ||
3810 | break; | ||
3811 | }; | ||
3789 | 3812 | ||
3790 | ptr += opsize-2; | 3813 | ptr += opsize-2; |
3791 | length -= opsize; | 3814 | length -= opsize; |
@@ -3813,17 +3836,20 @@ static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th) | |||
3813 | * If it is wrong it falls back on tcp_parse_options(). | 3836 | * If it is wrong it falls back on tcp_parse_options(). |
3814 | */ | 3837 | */ |
3815 | static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th, | 3838 | static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th, |
3816 | struct tcp_sock *tp) | 3839 | struct tcp_sock *tp, u8 **hvpp) |
3817 | { | 3840 | { |
3818 | if (th->doff == sizeof(struct tcphdr) >> 2) { | 3841 | /* In the spirit of fast parsing, compare doff directly to constant |
3842 | * values. Because equality is used, short doff can be ignored here. | ||
3843 | */ | ||
3844 | if (th->doff == (sizeof(*th) / 4)) { | ||
3819 | tp->rx_opt.saw_tstamp = 0; | 3845 | tp->rx_opt.saw_tstamp = 0; |
3820 | return 0; | 3846 | return 0; |
3821 | } else if (tp->rx_opt.tstamp_ok && | 3847 | } else if (tp->rx_opt.tstamp_ok && |
3822 | th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) { | 3848 | th->doff == ((sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) / 4)) { |
3823 | if (tcp_parse_aligned_timestamp(tp, th)) | 3849 | if (tcp_parse_aligned_timestamp(tp, th)) |
3824 | return 1; | 3850 | return 1; |
3825 | } | 3851 | } |
3826 | tcp_parse_options(skb, &tp->rx_opt, 1, NULL); | 3852 | tcp_parse_options(skb, &tp->rx_opt, hvpp, 1, NULL); |
3827 | return 1; | 3853 | return 1; |
3828 | } | 3854 | } |
3829 | 3855 | ||
@@ -5077,10 +5103,12 @@ out: | |||
5077 | static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, | 5103 | static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, |
5078 | struct tcphdr *th, int syn_inerr) | 5104 | struct tcphdr *th, int syn_inerr) |
5079 | { | 5105 | { |
5106 | u8 *hash_location; | ||
5080 | struct tcp_sock *tp = tcp_sk(sk); | 5107 | struct tcp_sock *tp = tcp_sk(sk); |
5081 | 5108 | ||
5082 | /* RFC1323: H1. Apply PAWS check first. */ | 5109 | /* RFC1323: H1. Apply PAWS check first. */ |
5083 | if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp && | 5110 | if (tcp_fast_parse_options(skb, th, tp, &hash_location) && |
5111 | tp->rx_opt.saw_tstamp && | ||
5084 | tcp_paws_discard(sk, skb)) { | 5112 | tcp_paws_discard(sk, skb)) { |
5085 | if (!th->rst) { | 5113 | if (!th->rst) { |
5086 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); | 5114 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); |
@@ -5368,12 +5396,14 @@ discard: | |||
5368 | static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, | 5396 | static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, |
5369 | struct tcphdr *th, unsigned len) | 5397 | struct tcphdr *th, unsigned len) |
5370 | { | 5398 | { |
5371 | struct tcp_sock *tp = tcp_sk(sk); | 5399 | u8 *hash_location; |
5372 | struct inet_connection_sock *icsk = inet_csk(sk); | 5400 | struct inet_connection_sock *icsk = inet_csk(sk); |
5373 | int saved_clamp = tp->rx_opt.mss_clamp; | 5401 | struct tcp_sock *tp = tcp_sk(sk); |
5374 | struct dst_entry *dst = __sk_dst_get(sk); | 5402 | struct dst_entry *dst = __sk_dst_get(sk); |
5403 | struct tcp_cookie_values *cvp = tp->cookie_values; | ||
5404 | int saved_clamp = tp->rx_opt.mss_clamp; | ||
5375 | 5405 | ||
5376 | tcp_parse_options(skb, &tp->rx_opt, 0, dst); | 5406 | tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, dst); |
5377 | 5407 | ||
5378 | if (th->ack) { | 5408 | if (th->ack) { |
5379 | /* rfc793: | 5409 | /* rfc793: |
@@ -5470,6 +5500,31 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, | |||
5470 | * Change state from SYN-SENT only after copied_seq | 5500 | * Change state from SYN-SENT only after copied_seq |
5471 | * is initialized. */ | 5501 | * is initialized. */ |
5472 | tp->copied_seq = tp->rcv_nxt; | 5502 | tp->copied_seq = tp->rcv_nxt; |
5503 | |||
5504 | if (cvp != NULL && | ||
5505 | cvp->cookie_pair_size > 0 && | ||
5506 | tp->rx_opt.cookie_plus > 0) { | ||
5507 | int cookie_size = tp->rx_opt.cookie_plus | ||
5508 | - TCPOLEN_COOKIE_BASE; | ||
5509 | int cookie_pair_size = cookie_size | ||
5510 | + cvp->cookie_desired; | ||
5511 | |||
5512 | /* A cookie extension option was sent and returned. | ||
5513 | * Note that each incoming SYNACK replaces the | ||
5514 | * Responder cookie. The initial exchange is most | ||
5515 | * fragile, as protection against spoofing relies | ||
5516 | * entirely upon the sequence and timestamp (above). | ||
5517 | * This replacement strategy allows the correct pair to | ||
5518 | * pass through, while any others will be filtered via | ||
5519 | * Responder verification later. | ||
5520 | */ | ||
5521 | if (sizeof(cvp->cookie_pair) >= cookie_pair_size) { | ||
5522 | memcpy(&cvp->cookie_pair[cvp->cookie_desired], | ||
5523 | hash_location, cookie_size); | ||
5524 | cvp->cookie_pair_size = cookie_pair_size; | ||
5525 | } | ||
5526 | } | ||
5527 | |||
5473 | smp_mb(); | 5528 | smp_mb(); |
5474 | tcp_set_state(sk, TCP_ESTABLISHED); | 5529 | tcp_set_state(sk, TCP_ESTABLISHED); |
5475 | 5530 | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a2bcac9b388e..59c911f3889d 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1213,9 +1213,12 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = { | |||
1213 | 1213 | ||
1214 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | 1214 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) |
1215 | { | 1215 | { |
1216 | struct tcp_extend_values tmp_ext; | ||
1216 | struct tcp_options_received tmp_opt; | 1217 | struct tcp_options_received tmp_opt; |
1218 | u8 *hash_location; | ||
1217 | struct request_sock *req; | 1219 | struct request_sock *req; |
1218 | struct inet_request_sock *ireq; | 1220 | struct inet_request_sock *ireq; |
1221 | struct tcp_sock *tp = tcp_sk(sk); | ||
1219 | struct dst_entry *dst = NULL; | 1222 | struct dst_entry *dst = NULL; |
1220 | __be32 saddr = ip_hdr(skb)->saddr; | 1223 | __be32 saddr = ip_hdr(skb)->saddr; |
1221 | __be32 daddr = ip_hdr(skb)->daddr; | 1224 | __be32 daddr = ip_hdr(skb)->daddr; |
@@ -1271,15 +1274,49 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1271 | 1274 | ||
1272 | tcp_clear_options(&tmp_opt); | 1275 | tcp_clear_options(&tmp_opt); |
1273 | tmp_opt.mss_clamp = TCP_MSS_DEFAULT; | 1276 | tmp_opt.mss_clamp = TCP_MSS_DEFAULT; |
1274 | tmp_opt.user_mss = tcp_sk(sk)->rx_opt.user_mss; | 1277 | tmp_opt.user_mss = tp->rx_opt.user_mss; |
1278 | tcp_parse_options(skb, &tmp_opt, &hash_location, 0, dst); | ||
1279 | |||
1280 | if (tmp_opt.cookie_plus > 0 && | ||
1281 | tmp_opt.saw_tstamp && | ||
1282 | !tp->rx_opt.cookie_out_never && | ||
1283 | (sysctl_tcp_cookie_size > 0 || | ||
1284 | (tp->cookie_values != NULL && | ||
1285 | tp->cookie_values->cookie_desired > 0))) { | ||
1286 | u8 *c; | ||
1287 | u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS]; | ||
1288 | int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE; | ||
1289 | |||
1290 | if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0) | ||
1291 | goto drop_and_release; | ||
1292 | |||
1293 | /* Secret recipe starts with IP addresses */ | ||
1294 | *mess++ ^= daddr; | ||
1295 | *mess++ ^= saddr; | ||
1275 | 1296 | ||
1276 | tcp_parse_options(skb, &tmp_opt, 0, dst); | 1297 | /* plus variable length Initiator Cookie */ |
1298 | c = (u8 *)mess; | ||
1299 | while (l-- > 0) | ||
1300 | *c++ ^= *hash_location++; | ||
1301 | |||
1302 | #ifdef CONFIG_SYN_COOKIES | ||
1303 | want_cookie = 0; /* not our kind of cookie */ | ||
1304 | #endif | ||
1305 | tmp_ext.cookie_out_never = 0; /* false */ | ||
1306 | tmp_ext.cookie_plus = tmp_opt.cookie_plus; | ||
1307 | } else if (!tp->rx_opt.cookie_in_always) { | ||
1308 | /* redundant indications, but ensure initialization. */ | ||
1309 | tmp_ext.cookie_out_never = 1; /* true */ | ||
1310 | tmp_ext.cookie_plus = 0; | ||
1311 | } else { | ||
1312 | goto drop_and_release; | ||
1313 | } | ||
1314 | tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always; | ||
1277 | 1315 | ||
1278 | if (want_cookie && !tmp_opt.saw_tstamp) | 1316 | if (want_cookie && !tmp_opt.saw_tstamp) |
1279 | tcp_clear_options(&tmp_opt); | 1317 | tcp_clear_options(&tmp_opt); |
1280 | 1318 | ||
1281 | tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; | 1319 | tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; |
1282 | |||
1283 | tcp_openreq_init(req, &tmp_opt, skb); | 1320 | tcp_openreq_init(req, &tmp_opt, skb); |
1284 | 1321 | ||
1285 | if (security_inet_conn_request(sk, skb, req)) | 1322 | if (security_inet_conn_request(sk, skb, req)) |
@@ -1339,7 +1376,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1339 | } | 1376 | } |
1340 | tcp_rsk(req)->snt_isn = isn; | 1377 | tcp_rsk(req)->snt_isn = isn; |
1341 | 1378 | ||
1342 | if (__tcp_v4_send_synack(sk, dst, req, NULL) || want_cookie) | 1379 | if (__tcp_v4_send_synack(sk, dst, req, |
1380 | (struct request_values *)&tmp_ext) || | ||
1381 | want_cookie) | ||
1343 | goto drop_and_free; | 1382 | goto drop_and_free; |
1344 | 1383 | ||
1345 | inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 1384 | inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); |
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 96852af43ca7..87accec8d097 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -90,13 +90,14 @@ enum tcp_tw_status | |||
90 | tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, | 90 | tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, |
91 | const struct tcphdr *th) | 91 | const struct tcphdr *th) |
92 | { | 92 | { |
93 | struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); | ||
94 | struct tcp_options_received tmp_opt; | 93 | struct tcp_options_received tmp_opt; |
94 | u8 *hash_location; | ||
95 | struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); | ||
95 | int paws_reject = 0; | 96 | int paws_reject = 0; |
96 | 97 | ||
97 | if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { | 98 | if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { |
98 | tmp_opt.tstamp_ok = 1; | 99 | tmp_opt.tstamp_ok = 1; |
99 | tcp_parse_options(skb, &tmp_opt, 1, NULL); | 100 | tcp_parse_options(skb, &tmp_opt, &hash_location, 1, NULL); |
100 | 101 | ||
101 | if (tmp_opt.saw_tstamp) { | 102 | if (tmp_opt.saw_tstamp) { |
102 | tmp_opt.ts_recent = tcptw->tw_ts_recent; | 103 | tmp_opt.ts_recent = tcptw->tw_ts_recent; |
@@ -518,15 +519,16 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, | |||
518 | struct request_sock *req, | 519 | struct request_sock *req, |
519 | struct request_sock **prev) | 520 | struct request_sock **prev) |
520 | { | 521 | { |
522 | struct tcp_options_received tmp_opt; | ||
523 | u8 *hash_location; | ||
524 | struct sock *child; | ||
521 | const struct tcphdr *th = tcp_hdr(skb); | 525 | const struct tcphdr *th = tcp_hdr(skb); |
522 | __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); | 526 | __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); |
523 | int paws_reject = 0; | 527 | int paws_reject = 0; |
524 | struct tcp_options_received tmp_opt; | ||
525 | struct sock *child; | ||
526 | 528 | ||
527 | if ((th->doff > (sizeof(struct tcphdr)>>2)) && (req->ts_recent)) { | 529 | if ((th->doff > (sizeof(*th) >> 2)) && (req->ts_recent)) { |
528 | tmp_opt.tstamp_ok = 1; | 530 | tmp_opt.tstamp_ok = 1; |
529 | tcp_parse_options(skb, &tmp_opt, 1, NULL); | 531 | tcp_parse_options(skb, &tmp_opt, &hash_location, 1, NULL); |
530 | 532 | ||
531 | if (tmp_opt.saw_tstamp) { | 533 | if (tmp_opt.saw_tstamp) { |
532 | tmp_opt.ts_recent = req->ts_recent; | 534 | tmp_opt.ts_recent = req->ts_recent; |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 35dd983a8a99..2ac8beff4d77 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -655,48 +655,77 @@ static unsigned tcp_synack_options(struct sock *sk, | |||
655 | struct request_sock *req, | 655 | struct request_sock *req, |
656 | unsigned mss, struct sk_buff *skb, | 656 | unsigned mss, struct sk_buff *skb, |
657 | struct tcp_out_options *opts, | 657 | struct tcp_out_options *opts, |
658 | struct tcp_md5sig_key **md5) { | 658 | struct tcp_md5sig_key **md5, |
659 | unsigned size = 0; | 659 | struct tcp_extend_values *xvp) |
660 | { | ||
660 | struct inet_request_sock *ireq = inet_rsk(req); | 661 | struct inet_request_sock *ireq = inet_rsk(req); |
661 | char doing_ts; | 662 | unsigned remaining = MAX_TCP_OPTION_SPACE; |
663 | u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ? | ||
664 | xvp->cookie_plus : | ||
665 | 0; | ||
666 | bool doing_ts = ireq->tstamp_ok; | ||
662 | 667 | ||
663 | #ifdef CONFIG_TCP_MD5SIG | 668 | #ifdef CONFIG_TCP_MD5SIG |
664 | *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); | 669 | *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); |
665 | if (*md5) { | 670 | if (*md5) { |
666 | opts->options |= OPTION_MD5; | 671 | opts->options |= OPTION_MD5; |
667 | size += TCPOLEN_MD5SIG_ALIGNED; | 672 | remaining -= TCPOLEN_MD5SIG_ALIGNED; |
673 | |||
674 | /* We can't fit any SACK blocks in a packet with MD5 + TS | ||
675 | * options. There was discussion about disabling SACK | ||
676 | * rather than TS in order to fit in better with old, | ||
677 | * buggy kernels, but that was deemed to be unnecessary. | ||
678 | */ | ||
679 | doing_ts &= !ireq->sack_ok; | ||
668 | } | 680 | } |
669 | #else | 681 | #else |
670 | *md5 = NULL; | 682 | *md5 = NULL; |
671 | #endif | 683 | #endif |
672 | 684 | ||
673 | /* we can't fit any SACK blocks in a packet with MD5 + TS | 685 | /* We always send an MSS option. */ |
674 | options. There was discussion about disabling SACK rather than TS in | ||
675 | order to fit in better with old, buggy kernels, but that was deemed | ||
676 | to be unnecessary. */ | ||
677 | doing_ts = ireq->tstamp_ok && !(*md5 && ireq->sack_ok); | ||
678 | |||
679 | opts->mss = mss; | 686 | opts->mss = mss; |
680 | size += TCPOLEN_MSS_ALIGNED; | 687 | remaining -= TCPOLEN_MSS_ALIGNED; |
681 | 688 | ||
682 | if (likely(ireq->wscale_ok)) { | 689 | if (likely(ireq->wscale_ok)) { |
683 | opts->ws = ireq->rcv_wscale; | 690 | opts->ws = ireq->rcv_wscale; |
684 | opts->options |= OPTION_WSCALE; | 691 | opts->options |= OPTION_WSCALE; |
685 | size += TCPOLEN_WSCALE_ALIGNED; | 692 | remaining -= TCPOLEN_WSCALE_ALIGNED; |
686 | } | 693 | } |
687 | if (likely(doing_ts)) { | 694 | if (likely(doing_ts)) { |
688 | opts->options |= OPTION_TS; | 695 | opts->options |= OPTION_TS; |
689 | opts->tsval = TCP_SKB_CB(skb)->when; | 696 | opts->tsval = TCP_SKB_CB(skb)->when; |
690 | opts->tsecr = req->ts_recent; | 697 | opts->tsecr = req->ts_recent; |
691 | size += TCPOLEN_TSTAMP_ALIGNED; | 698 | remaining -= TCPOLEN_TSTAMP_ALIGNED; |
692 | } | 699 | } |
693 | if (likely(ireq->sack_ok)) { | 700 | if (likely(ireq->sack_ok)) { |
694 | opts->options |= OPTION_SACK_ADVERTISE; | 701 | opts->options |= OPTION_SACK_ADVERTISE; |
695 | if (unlikely(!doing_ts)) | 702 | if (unlikely(!doing_ts)) |
696 | size += TCPOLEN_SACKPERM_ALIGNED; | 703 | remaining -= TCPOLEN_SACKPERM_ALIGNED; |
697 | } | 704 | } |
698 | 705 | ||
699 | return size; | 706 | /* Similar rationale to tcp_syn_options() applies here, too. |
707 | * If the <SYN> options fit, the same options should fit now! | ||
708 | */ | ||
709 | if (*md5 == NULL && | ||
710 | doing_ts && | ||
711 | cookie_plus > TCPOLEN_COOKIE_BASE) { | ||
712 | int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */ | ||
713 | |||
714 | if (0x2 & need) { | ||
715 | /* 32-bit multiple */ | ||
716 | need += 2; /* NOPs */ | ||
717 | } | ||
718 | if (need <= remaining) { | ||
719 | opts->options |= OPTION_COOKIE_EXTENSION; | ||
720 | opts->hash_size = cookie_plus - TCPOLEN_COOKIE_BASE; | ||
721 | remaining -= need; | ||
722 | } else { | ||
723 | /* There's no error return, so flag it. */ | ||
724 | xvp->cookie_out_never = 1; /* true */ | ||
725 | opts->hash_size = 0; | ||
726 | } | ||
727 | } | ||
728 | return MAX_TCP_OPTION_SPACE - remaining; | ||
700 | } | 729 | } |
701 | 730 | ||
702 | /* Compute TCP options for ESTABLISHED sockets. This is not the | 731 | /* Compute TCP options for ESTABLISHED sockets. This is not the |
@@ -2365,6 +2394,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2365 | struct request_values *rvp) | 2394 | struct request_values *rvp) |
2366 | { | 2395 | { |
2367 | struct tcp_out_options opts; | 2396 | struct tcp_out_options opts; |
2397 | struct tcp_extend_values *xvp = tcp_xv(rvp); | ||
2368 | struct inet_request_sock *ireq = inet_rsk(req); | 2398 | struct inet_request_sock *ireq = inet_rsk(req); |
2369 | struct tcp_sock *tp = tcp_sk(sk); | 2399 | struct tcp_sock *tp = tcp_sk(sk); |
2370 | struct tcphdr *th; | 2400 | struct tcphdr *th; |
@@ -2408,8 +2438,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2408 | #endif | 2438 | #endif |
2409 | TCP_SKB_CB(skb)->when = tcp_time_stamp; | 2439 | TCP_SKB_CB(skb)->when = tcp_time_stamp; |
2410 | tcp_header_size = tcp_synack_options(sk, req, mss, | 2440 | tcp_header_size = tcp_synack_options(sk, req, mss, |
2411 | skb, &opts, &md5) + | 2441 | skb, &opts, &md5, xvp) |
2412 | sizeof(struct tcphdr); | 2442 | + sizeof(*th); |
2413 | 2443 | ||
2414 | skb_push(skb, tcp_header_size); | 2444 | skb_push(skb, tcp_header_size); |
2415 | skb_reset_transport_header(skb); | 2445 | skb_reset_transport_header(skb); |
@@ -2426,6 +2456,45 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2426 | */ | 2456 | */ |
2427 | tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn, | 2457 | tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn, |
2428 | TCPCB_FLAG_SYN | TCPCB_FLAG_ACK); | 2458 | TCPCB_FLAG_SYN | TCPCB_FLAG_ACK); |
2459 | |||
2460 | if (OPTION_COOKIE_EXTENSION & opts.options) { | ||
2461 | const struct tcp_cookie_values *cvp = tp->cookie_values; | ||
2462 | |||
2463 | if (cvp != NULL && | ||
2464 | cvp->s_data_constant && | ||
2465 | cvp->s_data_desired > 0) { | ||
2466 | u8 *buf = skb_put(skb, cvp->s_data_desired); | ||
2467 | |||
2468 | /* copy data directly from the listening socket. */ | ||
2469 | memcpy(buf, cvp->s_data_payload, cvp->s_data_desired); | ||
2470 | TCP_SKB_CB(skb)->end_seq += cvp->s_data_desired; | ||
2471 | } | ||
2472 | |||
2473 | if (opts.hash_size > 0) { | ||
2474 | __u32 workspace[SHA_WORKSPACE_WORDS]; | ||
2475 | u32 *mess = &xvp->cookie_bakery[COOKIE_DIGEST_WORDS]; | ||
2476 | u32 *tail = &mess[COOKIE_MESSAGE_WORDS-1]; | ||
2477 | |||
2478 | /* Secret recipe depends on the Timestamp, (future) | ||
2479 | * Sequence and Acknowledgment Numbers, Initiator | ||
2480 | * Cookie, and others handled by IP variant caller. | ||
2481 | */ | ||
2482 | *tail-- ^= opts.tsval; | ||
2483 | *tail-- ^= tcp_rsk(req)->rcv_isn + 1; | ||
2484 | *tail-- ^= TCP_SKB_CB(skb)->seq + 1; | ||
2485 | |||
2486 | /* recommended */ | ||
2487 | *tail-- ^= ((th->dest << 16) | th->source); | ||
2488 | *tail-- ^= (u32)cvp; /* per sockopt */ | ||
2489 | |||
2490 | sha_transform((__u32 *)&xvp->cookie_bakery[0], | ||
2491 | (char *)mess, | ||
2492 | &workspace[0]); | ||
2493 | opts.hash_location = | ||
2494 | (__u8 *)&xvp->cookie_bakery[0]; | ||
2495 | } | ||
2496 | } | ||
2497 | |||
2429 | th->seq = htonl(TCP_SKB_CB(skb)->seq); | 2498 | th->seq = htonl(TCP_SKB_CB(skb)->seq); |
2430 | th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); | 2499 | th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); |
2431 | 2500 | ||
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 612fc53e0bb9..5b9af508b8f2 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -159,6 +159,8 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie) | |||
159 | 159 | ||
160 | struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | 160 | struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) |
161 | { | 161 | { |
162 | struct tcp_options_received tcp_opt; | ||
163 | u8 *hash_location; | ||
162 | struct inet_request_sock *ireq; | 164 | struct inet_request_sock *ireq; |
163 | struct inet6_request_sock *ireq6; | 165 | struct inet6_request_sock *ireq6; |
164 | struct tcp_request_sock *treq; | 166 | struct tcp_request_sock *treq; |
@@ -171,7 +173,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
171 | int mss; | 173 | int mss; |
172 | struct dst_entry *dst; | 174 | struct dst_entry *dst; |
173 | __u8 rcv_wscale; | 175 | __u8 rcv_wscale; |
174 | struct tcp_options_received tcp_opt; | ||
175 | 176 | ||
176 | if (!sysctl_tcp_syncookies || !th->ack) | 177 | if (!sysctl_tcp_syncookies || !th->ack) |
177 | goto out; | 178 | goto out; |
@@ -254,7 +255,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
254 | 255 | ||
255 | /* check for timestamp cookie support */ | 256 | /* check for timestamp cookie support */ |
256 | memset(&tcp_opt, 0, sizeof(tcp_opt)); | 257 | memset(&tcp_opt, 0, sizeof(tcp_opt)); |
257 | tcp_parse_options(skb, &tcp_opt, 0, dst); | 258 | tcp_parse_options(skb, &tcp_opt, &hash_location, 0, dst); |
258 | 259 | ||
259 | if (tcp_opt.saw_tstamp) | 260 | if (tcp_opt.saw_tstamp) |
260 | cookie_check_timestamp(&tcp_opt); | 261 | cookie_check_timestamp(&tcp_opt); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f2ec38289a4a..fc0a4e5895ee 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -1162,7 +1162,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | |||
1162 | */ | 1162 | */ |
1163 | static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | 1163 | static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) |
1164 | { | 1164 | { |
1165 | struct tcp_extend_values tmp_ext; | ||
1165 | struct tcp_options_received tmp_opt; | 1166 | struct tcp_options_received tmp_opt; |
1167 | u8 *hash_location; | ||
1166 | struct request_sock *req; | 1168 | struct request_sock *req; |
1167 | struct inet6_request_sock *treq; | 1169 | struct inet6_request_sock *treq; |
1168 | struct ipv6_pinfo *np = inet6_sk(sk); | 1170 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -1206,8 +1208,52 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1206 | tcp_clear_options(&tmp_opt); | 1208 | tcp_clear_options(&tmp_opt); |
1207 | tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); | 1209 | tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); |
1208 | tmp_opt.user_mss = tp->rx_opt.user_mss; | 1210 | tmp_opt.user_mss = tp->rx_opt.user_mss; |
1211 | tcp_parse_options(skb, &tmp_opt, &hash_location, 0, dst); | ||
1212 | |||
1213 | if (tmp_opt.cookie_plus > 0 && | ||
1214 | tmp_opt.saw_tstamp && | ||
1215 | !tp->rx_opt.cookie_out_never && | ||
1216 | (sysctl_tcp_cookie_size > 0 || | ||
1217 | (tp->cookie_values != NULL && | ||
1218 | tp->cookie_values->cookie_desired > 0))) { | ||
1219 | u8 *c; | ||
1220 | u32 *d; | ||
1221 | u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS]; | ||
1222 | int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE; | ||
1223 | |||
1224 | if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0) | ||
1225 | goto drop_and_free; | ||
1226 | |||
1227 | /* Secret recipe starts with IP addresses */ | ||
1228 | d = &ipv6_hdr(skb)->daddr.s6_addr32[0]; | ||
1229 | *mess++ ^= *d++; | ||
1230 | *mess++ ^= *d++; | ||
1231 | *mess++ ^= *d++; | ||
1232 | *mess++ ^= *d++; | ||
1233 | d = &ipv6_hdr(skb)->saddr.s6_addr32[0]; | ||
1234 | *mess++ ^= *d++; | ||
1235 | *mess++ ^= *d++; | ||
1236 | *mess++ ^= *d++; | ||
1237 | *mess++ ^= *d++; | ||
1238 | |||
1239 | /* plus variable length Initiator Cookie */ | ||
1240 | c = (u8 *)mess; | ||
1241 | while (l-- > 0) | ||
1242 | *c++ ^= *hash_location++; | ||
1209 | 1243 | ||
1210 | tcp_parse_options(skb, &tmp_opt, 0, dst); | 1244 | #ifdef CONFIG_SYN_COOKIES |
1245 | want_cookie = 0; /* not our kind of cookie */ | ||
1246 | #endif | ||
1247 | tmp_ext.cookie_out_never = 0; /* false */ | ||
1248 | tmp_ext.cookie_plus = tmp_opt.cookie_plus; | ||
1249 | } else if (!tp->rx_opt.cookie_in_always) { | ||
1250 | /* redundant indications, but ensure initialization. */ | ||
1251 | tmp_ext.cookie_out_never = 1; /* true */ | ||
1252 | tmp_ext.cookie_plus = 0; | ||
1253 | } else { | ||
1254 | goto drop_and_free; | ||
1255 | } | ||
1256 | tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always; | ||
1211 | 1257 | ||
1212 | if (want_cookie && !tmp_opt.saw_tstamp) | 1258 | if (want_cookie && !tmp_opt.saw_tstamp) |
1213 | tcp_clear_options(&tmp_opt); | 1259 | tcp_clear_options(&tmp_opt); |
@@ -1244,7 +1290,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1244 | 1290 | ||
1245 | security_inet_conn_request(sk, skb, req); | 1291 | security_inet_conn_request(sk, skb, req); |
1246 | 1292 | ||
1247 | if (tcp_v6_send_synack(sk, req, NULL) || want_cookie) | 1293 | if (tcp_v6_send_synack(sk, req, |
1294 | (struct request_values *)&tmp_ext) || | ||
1295 | want_cookie) | ||
1248 | goto drop_and_free; | 1296 | goto drop_and_free; |
1249 | 1297 | ||
1250 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 1298 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); |