aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorWilliam Allen Simpson <william.allen.simpson@gmail.com>2009-12-02 13:25:27 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-03 01:07:26 -0500
commit4957faade11b3a278c3b3cade3411ddc20afa791 (patch)
tree57f994bab69353baf5f554b89cf9107c3372ecce /net
parentbd0388ae77075026d6a9f9eb6026dfd1d52ce0e9 (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.c5
-rw-r--r--net/ipv4/tcp_input.c75
-rw-r--r--net/ipv4/tcp_ipv4.c47
-rw-r--r--net/ipv4/tcp_minisocks.c14
-rw-r--r--net/ipv4/tcp_output.c103
-rw-r--r--net/ipv6/syncookies.c5
-rw-r--r--net/ipv6/tcp_ipv6.c52
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);
253struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, 253struct 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 */
3700void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, 3700void 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 */
3815static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th, 3838static 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:
5077static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, 5103static 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:
5368static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, 5396static 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
1214int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) 1214int 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
90tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, 90tcp_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
160struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) 160struct 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 */
1163static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) 1163static 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);