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_input.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_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 75 |
1 files changed, 65 insertions, 10 deletions
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 | ||