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/ipv4/tcp_output.c | |
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/ipv4/tcp_output.c')
-rw-r--r-- | net/ipv4/tcp_output.c | 103 |
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 | ||