aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_output.c
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/ipv4/tcp_output.c
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/ipv4/tcp_output.c')
-rw-r--r--net/ipv4/tcp_output.c103
1 files changed, 86 insertions, 17 deletions
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