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>
This commit is contained in:
committed by
David S. Miller
parent
bd0388ae77
commit
4957faade1
@@ -3698,7 +3698,7 @@ old_ack:
|
||||
* the fast version below fails.
|
||||
*/
|
||||
void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
|
||||
int estab, struct dst_entry *dst)
|
||||
u8 **hvpp, int estab, struct dst_entry *dst)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
struct tcphdr *th = tcp_hdr(skb);
|
||||
@@ -3785,7 +3785,30 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
|
||||
*/
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
case TCPOPT_COOKIE:
|
||||
/* This option is variable length.
|
||||
*/
|
||||
switch (opsize) {
|
||||
case TCPOLEN_COOKIE_BASE:
|
||||
/* not yet implemented */
|
||||
break;
|
||||
case TCPOLEN_COOKIE_PAIR:
|
||||
/* not yet implemented */
|
||||
break;
|
||||
case TCPOLEN_COOKIE_MIN+0:
|
||||
case TCPOLEN_COOKIE_MIN+2:
|
||||
case TCPOLEN_COOKIE_MIN+4:
|
||||
case TCPOLEN_COOKIE_MIN+6:
|
||||
case TCPOLEN_COOKIE_MAX:
|
||||
/* 16-bit multiple */
|
||||
opt_rx->cookie_plus = opsize;
|
||||
*hvpp = ptr;
|
||||
default:
|
||||
/* ignore option */
|
||||
break;
|
||||
};
|
||||
break;
|
||||
};
|
||||
|
||||
ptr += opsize-2;
|
||||
length -= opsize;
|
||||
@@ -3813,17 +3836,20 @@ static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th)
|
||||
* If it is wrong it falls back on tcp_parse_options().
|
||||
*/
|
||||
static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
|
||||
struct tcp_sock *tp)
|
||||
struct tcp_sock *tp, u8 **hvpp)
|
||||
{
|
||||
if (th->doff == sizeof(struct tcphdr) >> 2) {
|
||||
/* In the spirit of fast parsing, compare doff directly to constant
|
||||
* values. Because equality is used, short doff can be ignored here.
|
||||
*/
|
||||
if (th->doff == (sizeof(*th) / 4)) {
|
||||
tp->rx_opt.saw_tstamp = 0;
|
||||
return 0;
|
||||
} else if (tp->rx_opt.tstamp_ok &&
|
||||
th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
|
||||
th->doff == ((sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) / 4)) {
|
||||
if (tcp_parse_aligned_timestamp(tp, th))
|
||||
return 1;
|
||||
}
|
||||
tcp_parse_options(skb, &tp->rx_opt, 1, NULL);
|
||||
tcp_parse_options(skb, &tp->rx_opt, hvpp, 1, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -5077,10 +5103,12 @@ out:
|
||||
static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
|
||||
struct tcphdr *th, int syn_inerr)
|
||||
{
|
||||
u8 *hash_location;
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
|
||||
/* RFC1323: H1. Apply PAWS check first. */
|
||||
if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
|
||||
if (tcp_fast_parse_options(skb, th, tp, &hash_location) &&
|
||||
tp->rx_opt.saw_tstamp &&
|
||||
tcp_paws_discard(sk, skb)) {
|
||||
if (!th->rst) {
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
|
||||
@@ -5368,12 +5396,14 @@ discard:
|
||||
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
|
||||
struct tcphdr *th, unsigned len)
|
||||
{
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
u8 *hash_location;
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
int saved_clamp = tp->rx_opt.mss_clamp;
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
struct dst_entry *dst = __sk_dst_get(sk);
|
||||
struct tcp_cookie_values *cvp = tp->cookie_values;
|
||||
int saved_clamp = tp->rx_opt.mss_clamp;
|
||||
|
||||
tcp_parse_options(skb, &tp->rx_opt, 0, dst);
|
||||
tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, dst);
|
||||
|
||||
if (th->ack) {
|
||||
/* rfc793:
|
||||
@@ -5470,6 +5500,31 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
|
||||
* Change state from SYN-SENT only after copied_seq
|
||||
* is initialized. */
|
||||
tp->copied_seq = tp->rcv_nxt;
|
||||
|
||||
if (cvp != NULL &&
|
||||
cvp->cookie_pair_size > 0 &&
|
||||
tp->rx_opt.cookie_plus > 0) {
|
||||
int cookie_size = tp->rx_opt.cookie_plus
|
||||
- TCPOLEN_COOKIE_BASE;
|
||||
int cookie_pair_size = cookie_size
|
||||
+ cvp->cookie_desired;
|
||||
|
||||
/* A cookie extension option was sent and returned.
|
||||
* Note that each incoming SYNACK replaces the
|
||||
* Responder cookie. The initial exchange is most
|
||||
* fragile, as protection against spoofing relies
|
||||
* entirely upon the sequence and timestamp (above).
|
||||
* This replacement strategy allows the correct pair to
|
||||
* pass through, while any others will be filtered via
|
||||
* Responder verification later.
|
||||
*/
|
||||
if (sizeof(cvp->cookie_pair) >= cookie_pair_size) {
|
||||
memcpy(&cvp->cookie_pair[cvp->cookie_desired],
|
||||
hash_location, cookie_size);
|
||||
cvp->cookie_pair_size = cookie_pair_size;
|
||||
}
|
||||
}
|
||||
|
||||
smp_mb();
|
||||
tcp_set_state(sk, TCP_ESTABLISHED);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user