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:
		
							parent
							
								
									bd0388ae77
								
							
						
					
					
						commit
						4957faade1
					
				| @ -407,6 +407,7 @@ extern int			tcp_recvmsg(struct kiocb *iocb, struct sock *sk, | ||||
| 
 | ||||
| extern void			tcp_parse_options(struct sk_buff *skb, | ||||
| 						  struct tcp_options_received *opt_rx, | ||||
| 						  u8 **hvpp, | ||||
| 						  int estab, | ||||
| 						  struct dst_entry *dst); | ||||
| 
 | ||||
|  | ||||
| @ -253,6 +253,8 @@ EXPORT_SYMBOL(cookie_check_timestamp); | ||||
| struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | ||||
| 			     struct ip_options *opt) | ||||
| { | ||||
| 	struct tcp_options_received tcp_opt; | ||||
| 	u8 *hash_location; | ||||
| 	struct inet_request_sock *ireq; | ||||
| 	struct tcp_request_sock *treq; | ||||
| 	struct tcp_sock *tp = tcp_sk(sk); | ||||
| @ -263,7 +265,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | ||||
| 	int mss; | ||||
| 	struct rtable *rt; | ||||
| 	__u8 rcv_wscale; | ||||
| 	struct tcp_options_received tcp_opt; | ||||
| 
 | ||||
| 	if (!sysctl_tcp_syncookies || !th->ack) | ||||
| 		goto out; | ||||
| @ -341,7 +342,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | ||||
| 
 | ||||
| 	/* check for timestamp cookie support */ | ||||
| 	memset(&tcp_opt, 0, sizeof(tcp_opt)); | ||||
| 	tcp_parse_options(skb, &tcp_opt, 0, &rt->u.dst); | ||||
| 	tcp_parse_options(skb, &tcp_opt, &hash_location, 0, &rt->u.dst); | ||||
| 
 | ||||
| 	if (tcp_opt.saw_tstamp) | ||||
| 		cookie_check_timestamp(&tcp_opt); | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
|  | ||||
| @ -1213,9 +1213,12 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = { | ||||
| 
 | ||||
| int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | ||||
| { | ||||
| 	struct tcp_extend_values tmp_ext; | ||||
| 	struct tcp_options_received tmp_opt; | ||||
| 	u8 *hash_location; | ||||
| 	struct request_sock *req; | ||||
| 	struct inet_request_sock *ireq; | ||||
| 	struct tcp_sock *tp = tcp_sk(sk); | ||||
| 	struct dst_entry *dst = NULL; | ||||
| 	__be32 saddr = ip_hdr(skb)->saddr; | ||||
| 	__be32 daddr = ip_hdr(skb)->daddr; | ||||
| @ -1271,15 +1274,49 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | ||||
| 
 | ||||
| 	tcp_clear_options(&tmp_opt); | ||||
| 	tmp_opt.mss_clamp = TCP_MSS_DEFAULT; | ||||
| 	tmp_opt.user_mss  = tcp_sk(sk)->rx_opt.user_mss; | ||||
| 	tmp_opt.user_mss  = tp->rx_opt.user_mss; | ||||
| 	tcp_parse_options(skb, &tmp_opt, &hash_location, 0, dst); | ||||
| 
 | ||||
| 	tcp_parse_options(skb, &tmp_opt, 0, dst); | ||||
| 	if (tmp_opt.cookie_plus > 0 && | ||||
| 	    tmp_opt.saw_tstamp && | ||||
| 	    !tp->rx_opt.cookie_out_never && | ||||
| 	    (sysctl_tcp_cookie_size > 0 || | ||||
| 	     (tp->cookie_values != NULL && | ||||
| 	      tp->cookie_values->cookie_desired > 0))) { | ||||
| 		u8 *c; | ||||
| 		u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS]; | ||||
| 		int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE; | ||||
| 
 | ||||
| 		if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0) | ||||
| 			goto drop_and_release; | ||||
| 
 | ||||
| 		/* Secret recipe starts with IP addresses */ | ||||
| 		*mess++ ^= daddr; | ||||
| 		*mess++ ^= saddr; | ||||
| 
 | ||||
| 		/* plus variable length Initiator Cookie */ | ||||
| 		c = (u8 *)mess; | ||||
| 		while (l-- > 0) | ||||
| 			*c++ ^= *hash_location++; | ||||
| 
 | ||||
| #ifdef CONFIG_SYN_COOKIES | ||||
| 		want_cookie = 0;	/* not our kind of cookie */ | ||||
| #endif | ||||
| 		tmp_ext.cookie_out_never = 0; /* false */ | ||||
| 		tmp_ext.cookie_plus = tmp_opt.cookie_plus; | ||||
| 	} else if (!tp->rx_opt.cookie_in_always) { | ||||
| 		/* redundant indications, but ensure initialization. */ | ||||
| 		tmp_ext.cookie_out_never = 1; /* true */ | ||||
| 		tmp_ext.cookie_plus = 0; | ||||
| 	} else { | ||||
| 		goto drop_and_release; | ||||
| 	} | ||||
| 	tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always; | ||||
| 
 | ||||
| 	if (want_cookie && !tmp_opt.saw_tstamp) | ||||
| 		tcp_clear_options(&tmp_opt); | ||||
| 
 | ||||
| 	tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; | ||||
| 
 | ||||
| 	tcp_openreq_init(req, &tmp_opt, skb); | ||||
| 
 | ||||
| 	if (security_inet_conn_request(sk, skb, req)) | ||||
| @ -1339,7 +1376,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | ||||
| 	} | ||||
| 	tcp_rsk(req)->snt_isn = isn; | ||||
| 
 | ||||
| 	if (__tcp_v4_send_synack(sk, dst, req, NULL) || want_cookie) | ||||
| 	if (__tcp_v4_send_synack(sk, dst, req, | ||||
| 				 (struct request_values *)&tmp_ext) || | ||||
| 	    want_cookie) | ||||
| 		goto drop_and_free; | ||||
| 
 | ||||
| 	inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | ||||
|  | ||||
| @ -90,13 +90,14 @@ enum tcp_tw_status | ||||
| tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, | ||||
| 			   const struct tcphdr *th) | ||||
| { | ||||
| 	struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); | ||||
| 	struct tcp_options_received tmp_opt; | ||||
| 	u8 *hash_location; | ||||
| 	struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); | ||||
| 	int paws_reject = 0; | ||||
| 
 | ||||
| 	if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { | ||||
| 		tmp_opt.tstamp_ok = 1; | ||||
| 		tcp_parse_options(skb, &tmp_opt, 1, NULL); | ||||
| 		tcp_parse_options(skb, &tmp_opt, &hash_location, 1, NULL); | ||||
| 
 | ||||
| 		if (tmp_opt.saw_tstamp) { | ||||
| 			tmp_opt.ts_recent	= tcptw->tw_ts_recent; | ||||
| @ -518,15 +519,16 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, | ||||
| 			   struct request_sock *req, | ||||
| 			   struct request_sock **prev) | ||||
| { | ||||
| 	struct tcp_options_received tmp_opt; | ||||
| 	u8 *hash_location; | ||||
| 	struct sock *child; | ||||
| 	const struct tcphdr *th = tcp_hdr(skb); | ||||
| 	__be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); | ||||
| 	int paws_reject = 0; | ||||
| 	struct tcp_options_received tmp_opt; | ||||
| 	struct sock *child; | ||||
| 
 | ||||
| 	if ((th->doff > (sizeof(struct tcphdr)>>2)) && (req->ts_recent)) { | ||||
| 	if ((th->doff > (sizeof(*th) >> 2)) && (req->ts_recent)) { | ||||
| 		tmp_opt.tstamp_ok = 1; | ||||
| 		tcp_parse_options(skb, &tmp_opt, 1, NULL); | ||||
| 		tcp_parse_options(skb, &tmp_opt, &hash_location, 1, NULL); | ||||
| 
 | ||||
| 		if (tmp_opt.saw_tstamp) { | ||||
| 			tmp_opt.ts_recent = req->ts_recent; | ||||
|  | ||||
| @ -655,48 +655,77 @@ static unsigned tcp_synack_options(struct sock *sk, | ||||
| 				   struct request_sock *req, | ||||
| 				   unsigned mss, struct sk_buff *skb, | ||||
| 				   struct tcp_out_options *opts, | ||||
| 				   struct tcp_md5sig_key **md5) { | ||||
| 	unsigned size = 0; | ||||
| 				   struct tcp_md5sig_key **md5, | ||||
| 				   struct tcp_extend_values *xvp) | ||||
| { | ||||
| 	struct inet_request_sock *ireq = inet_rsk(req); | ||||
| 	char doing_ts; | ||||
| 	unsigned remaining = MAX_TCP_OPTION_SPACE; | ||||
| 	u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ? | ||||
| 			 xvp->cookie_plus : | ||||
| 			 0; | ||||
| 	bool doing_ts = ireq->tstamp_ok; | ||||
| 
 | ||||
| #ifdef CONFIG_TCP_MD5SIG | ||||
| 	*md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); | ||||
| 	if (*md5) { | ||||
| 		opts->options |= OPTION_MD5; | ||||
| 		size += TCPOLEN_MD5SIG_ALIGNED; | ||||
| 		remaining -= TCPOLEN_MD5SIG_ALIGNED; | ||||
| 
 | ||||
| 		/* We can't fit any SACK blocks in a packet with MD5 + TS
 | ||||
| 		 * options. There was discussion about disabling SACK | ||||
| 		 * rather than TS in order to fit in better with old, | ||||
| 		 * buggy kernels, but that was deemed to be unnecessary. | ||||
| 		 */ | ||||
| 		doing_ts &= !ireq->sack_ok; | ||||
| 	} | ||||
| #else | ||||
| 	*md5 = NULL; | ||||
| #endif | ||||
| 
 | ||||
| 	/* we can't fit any SACK blocks in a packet with MD5 + TS
 | ||||
| 	   options. There was discussion about disabling SACK rather than TS in | ||||
| 	   order to fit in better with old, buggy kernels, but that was deemed | ||||
| 	   to be unnecessary. */ | ||||
| 	doing_ts = ireq->tstamp_ok && !(*md5 && ireq->sack_ok); | ||||
| 
 | ||||
| 	/* We always send an MSS option. */ | ||||
| 	opts->mss = mss; | ||||
| 	size += TCPOLEN_MSS_ALIGNED; | ||||
| 	remaining -= TCPOLEN_MSS_ALIGNED; | ||||
| 
 | ||||
| 	if (likely(ireq->wscale_ok)) { | ||||
| 		opts->ws = ireq->rcv_wscale; | ||||
| 		opts->options |= OPTION_WSCALE; | ||||
| 		size += TCPOLEN_WSCALE_ALIGNED; | ||||
| 		remaining -= TCPOLEN_WSCALE_ALIGNED; | ||||
| 	} | ||||
| 	if (likely(doing_ts)) { | ||||
| 		opts->options |= OPTION_TS; | ||||
| 		opts->tsval = TCP_SKB_CB(skb)->when; | ||||
| 		opts->tsecr = req->ts_recent; | ||||
| 		size += TCPOLEN_TSTAMP_ALIGNED; | ||||
| 		remaining -= TCPOLEN_TSTAMP_ALIGNED; | ||||
| 	} | ||||
| 	if (likely(ireq->sack_ok)) { | ||||
| 		opts->options |= OPTION_SACK_ADVERTISE; | ||||
| 		if (unlikely(!doing_ts)) | ||||
| 			size += TCPOLEN_SACKPERM_ALIGNED; | ||||
| 			remaining -= TCPOLEN_SACKPERM_ALIGNED; | ||||
| 	} | ||||
| 
 | ||||
| 	return size; | ||||
| 	/* Similar rationale to tcp_syn_options() applies here, too.
 | ||||
| 	 * If the <SYN> options fit, the same options should fit now! | ||||
| 	 */ | ||||
| 	if (*md5 == NULL && | ||||
| 	    doing_ts && | ||||
| 	    cookie_plus > TCPOLEN_COOKIE_BASE) { | ||||
| 		int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */ | ||||
| 
 | ||||
| 		if (0x2 & need) { | ||||
| 			/* 32-bit multiple */ | ||||
| 			need += 2; /* NOPs */ | ||||
| 		} | ||||
| 		if (need <= remaining) { | ||||
| 			opts->options |= OPTION_COOKIE_EXTENSION; | ||||
| 			opts->hash_size = cookie_plus - TCPOLEN_COOKIE_BASE; | ||||
| 			remaining -= need; | ||||
| 		} else { | ||||
| 			/* There's no error return, so flag it. */ | ||||
| 			xvp->cookie_out_never = 1; /* true */ | ||||
| 			opts->hash_size = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	return MAX_TCP_OPTION_SPACE - remaining; | ||||
| } | ||||
| 
 | ||||
| /* 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, | ||||
| 				struct request_values *rvp) | ||||
| { | ||||
| 	struct tcp_out_options opts; | ||||
| 	struct tcp_extend_values *xvp = tcp_xv(rvp); | ||||
| 	struct inet_request_sock *ireq = inet_rsk(req); | ||||
| 	struct tcp_sock *tp = tcp_sk(sk); | ||||
| 	struct tcphdr *th; | ||||
| @ -2408,8 +2438,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | ||||
| #endif | ||||
| 	TCP_SKB_CB(skb)->when = tcp_time_stamp; | ||||
| 	tcp_header_size = tcp_synack_options(sk, req, mss, | ||||
| 					     skb, &opts, &md5) + | ||||
| 			  sizeof(struct tcphdr); | ||||
| 					     skb, &opts, &md5, xvp) | ||||
| 			+ sizeof(*th); | ||||
| 
 | ||||
| 	skb_push(skb, tcp_header_size); | ||||
| 	skb_reset_transport_header(skb); | ||||
| @ -2426,6 +2456,45 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | ||||
| 	 */ | ||||
| 	tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn, | ||||
| 			     TCPCB_FLAG_SYN | TCPCB_FLAG_ACK); | ||||
| 
 | ||||
| 	if (OPTION_COOKIE_EXTENSION & opts.options) { | ||||
| 		const struct tcp_cookie_values *cvp = tp->cookie_values; | ||||
| 
 | ||||
| 		if (cvp != NULL && | ||||
| 		    cvp->s_data_constant && | ||||
| 		    cvp->s_data_desired > 0) { | ||||
| 			u8 *buf = skb_put(skb, cvp->s_data_desired); | ||||
| 
 | ||||
| 			/* copy data directly from the listening socket. */ | ||||
| 			memcpy(buf, cvp->s_data_payload, cvp->s_data_desired); | ||||
| 			TCP_SKB_CB(skb)->end_seq += cvp->s_data_desired; | ||||
| 		} | ||||
| 
 | ||||
| 		if (opts.hash_size > 0) { | ||||
| 			__u32 workspace[SHA_WORKSPACE_WORDS]; | ||||
| 			u32 *mess = &xvp->cookie_bakery[COOKIE_DIGEST_WORDS]; | ||||
| 			u32 *tail = &mess[COOKIE_MESSAGE_WORDS-1]; | ||||
| 
 | ||||
| 			/* Secret recipe depends on the Timestamp, (future)
 | ||||
| 			 * Sequence and Acknowledgment Numbers, Initiator | ||||
| 			 * Cookie, and others handled by IP variant caller. | ||||
| 			 */ | ||||
| 			*tail-- ^= opts.tsval; | ||||
| 			*tail-- ^= tcp_rsk(req)->rcv_isn + 1; | ||||
| 			*tail-- ^= TCP_SKB_CB(skb)->seq + 1; | ||||
| 
 | ||||
| 			/* recommended */ | ||||
| 			*tail-- ^= ((th->dest << 16) | th->source); | ||||
| 			*tail-- ^= (u32)cvp; /* per sockopt */ | ||||
| 
 | ||||
| 			sha_transform((__u32 *)&xvp->cookie_bakery[0], | ||||
| 				      (char *)mess, | ||||
| 				      &workspace[0]); | ||||
| 			opts.hash_location = | ||||
| 				(__u8 *)&xvp->cookie_bakery[0]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	th->seq = htonl(TCP_SKB_CB(skb)->seq); | ||||
| 	th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); | ||||
| 
 | ||||
|  | ||||
| @ -159,6 +159,8 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie) | ||||
| 
 | ||||
| struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | ||||
| { | ||||
| 	struct tcp_options_received tcp_opt; | ||||
| 	u8 *hash_location; | ||||
| 	struct inet_request_sock *ireq; | ||||
| 	struct inet6_request_sock *ireq6; | ||||
| 	struct tcp_request_sock *treq; | ||||
| @ -171,7 +173,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | ||||
| 	int mss; | ||||
| 	struct dst_entry *dst; | ||||
| 	__u8 rcv_wscale; | ||||
| 	struct tcp_options_received tcp_opt; | ||||
| 
 | ||||
| 	if (!sysctl_tcp_syncookies || !th->ack) | ||||
| 		goto out; | ||||
| @ -254,7 +255,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | ||||
| 
 | ||||
| 	/* check for timestamp cookie support */ | ||||
| 	memset(&tcp_opt, 0, sizeof(tcp_opt)); | ||||
| 	tcp_parse_options(skb, &tcp_opt, 0, dst); | ||||
| 	tcp_parse_options(skb, &tcp_opt, &hash_location, 0, dst); | ||||
| 
 | ||||
| 	if (tcp_opt.saw_tstamp) | ||||
| 		cookie_check_timestamp(&tcp_opt); | ||||
|  | ||||
| @ -1162,7 +1162,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | ||||
|  */ | ||||
| static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | ||||
| { | ||||
| 	struct tcp_extend_values tmp_ext; | ||||
| 	struct tcp_options_received tmp_opt; | ||||
| 	u8 *hash_location; | ||||
| 	struct request_sock *req; | ||||
| 	struct inet6_request_sock *treq; | ||||
| 	struct ipv6_pinfo *np = inet6_sk(sk); | ||||
| @ -1206,8 +1208,52 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | ||||
| 	tcp_clear_options(&tmp_opt); | ||||
| 	tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); | ||||
| 	tmp_opt.user_mss = tp->rx_opt.user_mss; | ||||
| 	tcp_parse_options(skb, &tmp_opt, &hash_location, 0, dst); | ||||
| 
 | ||||
| 	tcp_parse_options(skb, &tmp_opt, 0, dst); | ||||
| 	if (tmp_opt.cookie_plus > 0 && | ||||
| 	    tmp_opt.saw_tstamp && | ||||
| 	    !tp->rx_opt.cookie_out_never && | ||||
| 	    (sysctl_tcp_cookie_size > 0 || | ||||
| 	     (tp->cookie_values != NULL && | ||||
| 	      tp->cookie_values->cookie_desired > 0))) { | ||||
| 		u8 *c; | ||||
| 		u32 *d; | ||||
| 		u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS]; | ||||
| 		int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE; | ||||
| 
 | ||||
| 		if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0) | ||||
| 			goto drop_and_free; | ||||
| 
 | ||||
| 		/* Secret recipe starts with IP addresses */ | ||||
| 		d = &ipv6_hdr(skb)->daddr.s6_addr32[0]; | ||||
| 		*mess++ ^= *d++; | ||||
| 		*mess++ ^= *d++; | ||||
| 		*mess++ ^= *d++; | ||||
| 		*mess++ ^= *d++; | ||||
| 		d = &ipv6_hdr(skb)->saddr.s6_addr32[0]; | ||||
| 		*mess++ ^= *d++; | ||||
| 		*mess++ ^= *d++; | ||||
| 		*mess++ ^= *d++; | ||||
| 		*mess++ ^= *d++; | ||||
| 
 | ||||
| 		/* plus variable length Initiator Cookie */ | ||||
| 		c = (u8 *)mess; | ||||
| 		while (l-- > 0) | ||||
| 			*c++ ^= *hash_location++; | ||||
| 
 | ||||
| #ifdef CONFIG_SYN_COOKIES | ||||
| 		want_cookie = 0;	/* not our kind of cookie */ | ||||
| #endif | ||||
| 		tmp_ext.cookie_out_never = 0; /* false */ | ||||
| 		tmp_ext.cookie_plus = tmp_opt.cookie_plus; | ||||
| 	} else if (!tp->rx_opt.cookie_in_always) { | ||||
| 		/* redundant indications, but ensure initialization. */ | ||||
| 		tmp_ext.cookie_out_never = 1; /* true */ | ||||
| 		tmp_ext.cookie_plus = 0; | ||||
| 	} else { | ||||
| 		goto drop_and_free; | ||||
| 	} | ||||
| 	tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always; | ||||
| 
 | ||||
| 	if (want_cookie && !tmp_opt.saw_tstamp) | ||||
| 		tcp_clear_options(&tmp_opt); | ||||
| @ -1244,7 +1290,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | ||||
| 
 | ||||
| 	security_inet_conn_request(sk, skb, req); | ||||
| 
 | ||||
| 	if (tcp_v6_send_synack(sk, req, NULL) || want_cookie) | ||||
| 	if (tcp_v6_send_synack(sk, req, | ||||
| 			       (struct request_values *)&tmp_ext) || | ||||
| 	    want_cookie) | ||||
| 		goto drop_and_free; | ||||
| 
 | ||||
| 	inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user